Rectangle 27 50

The problem is that JAX-RS dictates that parameter unbundling be done in one of two ways:

  • The parameter bean has a public constructor that accepts a String
valueOf(String)

In your case, the Date is being unbundled via its Date(String) constructor, which cannot handle the input format your client is sending. You have a couple options available to remedy this:

Get your client to change the format of the date before they send it. This is the ideal, but probably the hardest to accomplish!

Handle the crazy date format. The options for this are:

Change your method signature to accept a string. Attempt to construct a Date object out of that and if that fails, use your own custom SimpleDateFormat class to parse it.

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);
    }
}

Define your own parameter class that does the logic mentioned above. Give it a string constructor or static valueOf(String) method that invokes the logic. And an additional method to get the Date when all is said and done.

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();
}

Or finally, you can register a parameter handler for dates. Where its logic is simply the same as mentioned for the other options above. Note that you need to be using at least CXF 2.5.3 in order to have your parameter handler evaluated before it tries the default unbundling logic.

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);
        }
    }
}

Reg. Option #1: In this case I'm distributing the client myself to users, so I'm free to choose a fixed date format if that helps. But the question is, how do I do this exactly? What determines which format the CXF client would use? I'd still to keep the java.util.Date as the QueryParam instead of changing to String or another DateParam like object to encapsulate a Date object inside.

Well if you have control over the client that makes things better. Just pass in any date format that can be handled by the Date(String) constructor. An example would be '12/20/2005 09:30:00 +0100' (mm/dd/yyy HH:MM:ss Z).

I do have control over the client, but my signature on both client & service side should be Date. Since on the client side, CXF internally calls toString() on my Date object while constructing the query parameters, how do I exercise my control and say use a specific date format and not the default one? Are you suggesting to extend Date and override toString() (which means the client signature will change)? Or is there any other mechanism which can be used on both client & service side to override the behavior? I guess MessageBodyReader/Wrtier is meant only for request body.

I have finally used ParameterHandler (third approach in Option 2). Since I have control on the client, I am directly parsing using the CRAZY_FORMAT (used by Date.toString()). Thanks Perception.

Just remember that SimpleDateFormat is NOT thread safe and putting 'static final' is wrong

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 48

The problem is that JAX-RS dictates that parameter unbundling be done in one of two ways:

  • The parameter bean has a public constructor that accepts a String
valueOf(String)

In your case, the Date is being unbundled via its Date(String) constructor, which cannot handle the input format your client is sending. You have a couple options available to remedy this:

Get your client to change the format of the date before they send it. This is the ideal, but probably the hardest to accomplish!

Handle the crazy date format. The options for this are:

Change your method signature to accept a string. Attempt to construct a Date object out of that and if that fails, use your own custom SimpleDateFormat class to parse it.

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);
    }
}

Define your own parameter class that does the logic mentioned above. Give it a string constructor or static valueOf(String) method that invokes the logic. And an additional method to get the Date when all is said and done.

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();
}

Or finally, you can register a parameter handler for dates. Where its logic is simply the same as mentioned for the other options above. Note that you need to be using at least CXF 2.5.3 in order to have your parameter handler evaluated before it tries the default unbundling logic.

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);
        }
    }
}

Reg. Option #1: In this case I'm distributing the client myself to users, so I'm free to choose a fixed date format if that helps. But the question is, how do I do this exactly? What determines which format the CXF client would use? I'd still to keep the java.util.Date as the QueryParam instead of changing to String or another DateParam like object to encapsulate a Date object inside.

Well if you have control over the client that makes things better. Just pass in any date format that can be handled by the Date(String) constructor. An example would be '12/20/2005 09:30:00 +0100' (mm/dd/yyy HH:MM:ss Z).

I do have control over the client, but my signature on both client & service side should be Date. Since on the client side, CXF internally calls toString() on my Date object while constructing the query parameters, how do I exercise my control and say use a specific date format and not the default one? Are you suggesting to extend Date and override toString() (which means the client signature will change)? Or is there any other mechanism which can be used on both client & service side to override the behavior? I guess MessageBodyReader/Wrtier is meant only for request body.

I have finally used ParameterHandler (third approach in Option 2). Since I have control on the client, I am directly parsing using the CRAZY_FORMAT (used by Date.toString()). Thanks Perception.

Just remember that SimpleDateFormat is NOT thread safe and putting 'static final' is wrong

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 8

ParameterHandler
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);
    }

}

The @SuppressWarnings is required to suppress an "unchecked or unsafe operations" warning during compilation. See How do I address unchecked cast warnings for more details.

The ParamConverterProvider can be registred as provider. Here is how I did it:

<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"/>

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 8

ParameterHandler
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);
    }

}

The @SuppressWarnings is required to suppress an "unchecked or unsafe operations" warning during compilation. See How do I address unchecked cast warnings for more details.

The ParamConverterProvider can be registred as provider. Here is how I did it:

<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"/>

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 1

Using a custom DateParam class seems the safest option. You can then base your method signatures on that and implement the ugly conversion logic inside the valueOf() method or the class constructor. It is also more self-documenting than using plain strings

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 1

Using a custom DateParam class seems the safest option. You can then base your method signatures on that and implement the ugly conversion logic inside the valueOf() method or the class constructor. It is also more self-documenting than using plain strings

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 0

You can register a custom date handler in Spring as follows:

<jaxrs:server >
    <jaxrs:providers>
        <bean class='.DateHandler' />
    </jaxrs:providers>
</jaxrs:server>

The date handler class itself can be pretty simple:

public class DateHandler implements ParameterHandler<Date> {
    @Override
    public Date fromString(String s) {
        Date ret = // do your magic
        return ret;
    }
}

This doesn't appear to be working for deserializing json? should it be (i may have some config issues?)

<bean class='org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider' />

java - Custom JSON Date handling in CXF - Stack Overflow

java json cxf jax-rs jettison
Rectangle 27 0

As @Perception suggests in option two, you can handle the date. But you should use following:

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);
    }
}

You call it from within the resource as

Date date = getDateFromString(dateString);//dateString is query param.

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 0

As @Perception suggests in option two, you can handle the date. But you should use following:

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);
    }
}

You call it from within the resource as

Date date = getDateFromString(dateString);//dateString is query param.

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 0

You can register a custom date handler in Spring as follows:

<jaxrs:server >
    <jaxrs:providers>
        <bean class='.DateHandler' />
    </jaxrs:providers>
</jaxrs:server>

The date handler class itself can be pretty simple:

public class DateHandler implements ParameterHandler<Date> {
    @Override
    public Date fromString(String s) {
        Date ret = // do your magic
        return ret;
    }
}

This doesn't appear to be working for deserializing json? should it be (i may have some config issues?)

<bean class='org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider' />

java - Custom JSON Date handling in CXF - Stack Overflow

java json cxf jax-rs jettison
Rectangle 27 0

By default wsdl's xsd:date gets mapped to XMLGregorianCalendar. If this is not what you want then if you are using CXF's wsdl to java tool then you can provide a binding file to override this default mapping:

<jaxws:bindings wsdlLocation="YOUR_WSDL_LOCATION"
          xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
          xmlns:xs="http://www.w3.org/2001/XMLSchema"
          xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
          xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <jaxws:bindings  node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='THE_NAMESPACE_OF_YOUR_SCHEMA']">
      <jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <jxb:javaType name="java.util.Date" xmlType="xs:date"
                      parseMethod="org.apache.cxf.tools.common.DataTypeAdapter.parseDate"
                      printMethod="org.apache.cxf.tools.common.DataTypeAdapter.printDate"/>
      </jxb:globalBindings>
  </jaxws:bindings>
</jaxws:bindings>

I actually LIKE the fact that it maps to XMLGregorianCalendar. I don't want to change that. I simply want to change the specific format the XMLGregorianCalendar gets rendered to in the resulting XML document.

Ok. I am not sure on that but can you try specifying a custom 'printMethod' in the above example given? Also retain the 'javaType' as XMLGregorianCalendar.

java - How do I represent dates without the timezone using Apache CXF?...

java web-services soap cxf
Rectangle 27 0

GregorianCalendar gcal = new GregorianCalendar();
start = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);
start.setTimezone(DatatypeConstants.FIELD_UNDEFINED);

Don't ask me why in every bit of the sane logic - when marshalling the XMLgregorianCalendar to xs:date it retains the time zone.

I always thought - the time zone could be more applicable to xs:dateTime, but what I know ... about types.

For me, it doesn't make sense to have the time zone by default, for a xs:date type and this is a problem in the marshalling logic.

Awesome. That did the trick for me (where custom JAXB bindings or other data types are not an option)

This was much easier for me than messing with binding files. Thanks!

java - How do I represent dates without the timezone using Apache CXF?...

java web-services soap cxf
Rectangle 27 0

As @Perception suggests in option two, you can handle the date. But you should use following:

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);
    }
}

You call it from within the resource as

Date date = getDateFromString(dateString);//dateString is query param.

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 0

The problem is that JAX-RS dictates that parameter unbundling be done in one of two ways:

  • The parameter bean has a public constructor that accepts a String
valueOf(String)

In your case, the Date is being unbundled via its Date(String) constructor, which cannot handle the input format your client is sending. You have a couple options available to remedy this:

Get your client to change the format of the date before they send it. This is the ideal, but probably the hardest to accomplish!

Handle the crazy date format. The options for this are:

Change your method signature to accept a string. Attempt to construct a Date object out of that and if that fails, use your own custom SimpleDateFormat class to parse it.

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);
    }
}

Define your own parameter class that does the logic mentioned above. Give it a string constructor or static valueOf(String) method that invokes the logic. And an additional method to get the Date when all is said and done.

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();
}

Or finally, you can register a parameter handler for dates. Where its logic is simply the same as mentioned for the other options above. Note that you need to be using at least CXF 2.5.3 in order to have your parameter handler evaluated before it tries the default unbundling logic.

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);
        }
    }
}

Reg. Option #1: In this case I'm distributing the client myself to users, so I'm free to choose a fixed date format if that helps. But the question is, how do I do this exactly? What determines which format the CXF client would use? I'd still to keep the java.util.Date as the QueryParam instead of changing to String or another DateParam like object to encapsulate a Date object inside.

Well if you have control over the client that makes things better. Just pass in any date format that can be handled by the Date(String) constructor. An example would be '12/20/2005 09:30:00 +0100' (mm/dd/yyy HH:MM:ss Z).

I do have control over the client, but my signature on both client & service side should be Date. Since on the client side, CXF internally calls toString() on my Date object while constructing the query parameters, how do I exercise my control and say use a specific date format and not the default one? Are you suggesting to extend Date and override toString() (which means the client signature will change)? Or is there any other mechanism which can be used on both client & service side to override the behavior? I guess MessageBodyReader/Wrtier is meant only for request body.

I have finally used ParameterHandler (third approach in Option 2). Since I have control on the client, I am directly parsing using the CRAZY_FORMAT (used by Date.toString()). Thanks Perception.

Just remember that SimpleDateFormat is NOT thread safe and putting 'static final' is wrong

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs
Rectangle 27 0

Using a custom DateParam class seems the safest option. You can then base your method signatures on that and implement the ugly conversion logic inside the valueOf() method or the class constructor. It is also more self-documenting than using plain strings

java - CXF JAXRS - How do I pass Date as QueryParam - Stack Overflow

java rest service cxf jax-rs