CXF JAXRS-Cómo paso la fecha como QueryParam


Tengo un servicio definido de la siguiente manera.

public String getData(@QueryParam("date") Date date)

Estoy tratando de pasarle un java.util.Date desde mi cliente (que es jaxrs:cliente de CXF, no un cliente HTTP genérico o navegador).

Mi servicio recibe la fecha como Thu Mar 01 22:33:10 IST 2012 en la URL HTTP. Dado que CXF no podrá crear un objeto Date usando esta cadena, mi cliente recibe un error 404. Traté de usar un ParameterHandler en el lado del servicio, pero todavía no puedo analizarlo con éxito porque no estoy esperando la fecha en ningún específico formato.

Según este post, pasar un Date se supone que funciona fuera de la caja, pero parece que no puedo conseguir que el caso básico funcione. ¿Estoy obligado a hacer algo para pasar con éxito un objeto de Fecha de mi cliente al servicio? Agradezco cualquier ayuda.

Gracias

Author: Community, 2012-03-01

4 answers

El problema es que JAX-RS dicta que la desagregación de parámetros se haga de una de dos maneras:

  1. El parámetro bean tiene un constructor público que acepta una cadena
  2. El parámetro bean tiene un método estático valueOf(String).

En su caso, la Fecha se está desagregando a través de su constructor Date(String), que no puede manejar el formato de entrada que su cliente está enviando. Usted tiene un par de opciones disponibles para remediar esto:


Opción 1

Haga que su cliente cambie el formato de la fecha antes de enviarla. Este es el ideal, pero probablemente el más difícil de lograr!


Opción 2

Maneja el formato de fecha loco. Las opciones para esto son:

Cambie la firma de su método para aceptar una cadena. Intente construir un objeto Date a partir de eso y, si falla, use su propia clase SimpleDateFormat personalizada para analizar se.

static final DateFormat CRAZY_FORMAT = new SimpleDateFormat("");

public String getData(@QueryParam("date") String dateString) {
    final Date date;
    try {
        date = new Date(dateString); // yes, I know this is a deprecated method
    } catch(Exception e) {
        date = CRAZY_FORMAT.parse(dateString);
    }
}

Defina su propia clase de parámetro que haga la lógica mencionada anteriormente. Dale un constructor de cadena o un método estático valueOf(String) que invoque la lógica. Y un método adicional para obtener la fecha cuando todo está dicho y hecho.

public class DateParameter implements Serializable {
    public static DateParameter valueOf(String dateString) {
        try {
            date = new Date(dateString); // yes, I know this is a deprecated method
        } catch(Exception e) {
            date = CRAZY_FORMAT.parse(dateString);
        }
    }

    private Date date;
    // Constructor, Getters, Setters
}

public String getData(@QueryParam("date") DateParameter dateParam) {
    final Date date = dateParam.getDate();
}

O, finalmente, puede registrar un controlador de parámetros para las fechas. Donde su lógica es simplemente la misma que se mencionó para las otras opciones anteriores. Tenga en cuenta que debe usar al menos CXF 2.5.3 para para que su controlador de parámetros sea evaluado antes de probar la lógica de desagregación predeterminada.

public class DateHandler implements ParameterHandler<Date> {
    public Map fromString(String s) {
        final Date date;
        try {
            date = new Date(dateString); // yes, I know this is a deprecated method
        } catch(Exception e) {
            date = CRAZY_FORMAT.parse(dateString);
        }
    }
}
 54
Author: Perception,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-01 19:26:32

La respuesta de Percepiton fue muy útil, pero ParameterHandler ha sido obsoleta en Apache-cxf 3.0, consulte la Guía de migración de Apache-cxf 3.0 :

CXF JAX-RS ParameterHandler ha sido eliminado, por favor utilice JAX-RS 2.0 ParamConverterProvider.

Así que añado un ejemplo con el ParamConverterProvider:

public class DateParameterConverterProvider implements ParamConverterProvider {

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> type, Type type1, Annotation[] antns) {
        if (Date.class.equals(type)) {
            @SuppressWarnings("unchecked")
            ParamConverter<T> paramConverter = (ParamConverter<T>) new DateParameterConverter();
            return paramConverter;
        }
        return null;
    }

}

public class DateParameterConverter implements ParamConverter<Date> {

    public static final String format = "yyyy-MM-dd"; // set the format to whatever you need

    @Override
    public Date fromString(String string) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        try {
            return simpleDateFormat.parse(string);
        } catch (ParseException ex) {
            throw new WebApplicationException(ex);
        }
    }

    @Override
    public String toString(Date t) {
        return new SimpleDateFormat(format).format(t);
    }

}

El @SuppressWarnings es necesario para suprimir una advertencia de "operaciones no verificadas o inseguras" durante la compilación. Ver ¿Cómo hago frente a las advertencias de reparto sin marcar para más detalles.

El ParamConverterProvider puede registrarse como proveedor. Así es como lo hice:

  <jaxrs:server id="myService" address="/rest">
      <jaxrs:serviceBeans>
           ...
      </jaxrs:serviceBeans>

      <jaxrs:providers>
          <ref bean="dateParameterConverterProvider" />
      </jaxrs:providers>
  </jaxrs:server>

  <bean id="dateParameterConverterProvider" class="myPackage.DateParameterConverterProvider"/>

Ver Apache-cxf JAX-RS : Services Configuration para más información.

 10
Author: Christophe Weis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:08

Usar una clase DateParam personalizada parece la opción más segura. A continuación, puede basar sus firmas de método en eso e implementar la lógica de conversión feo dentro del método valueOf() o el constructor de clase. También es más auto-documentada que usando cadenas simples

 1
Author: Cristian Botiza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-20 12:32:48

Como @Perception sugiere en la opción dos, puede manejar la fecha. Pero debes usar lo siguiente:

private Date getDateFromString(String dateString) {
    try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        Date date = df.parse(dateString);
        return date;
    } catch (ParseException e) {
        //WebApplicationException ...("Date format should be yyyy-MM-dd'T'HH:mm:ss", Status.BAD_REQUEST);
    }
}

Lo llamas desde dentro del recurso como

Date date = getDateFromString(dateString);//dateString is query param.
 0
Author: kasavbere,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-21 00:57:12