If have a resource with a POST method like this
@POST
@Consumes({"application/json"})
@Produces({"application/json"})
public Response createProfileExtensionSchema(ExtensionMetaDataRest extensionSchema, @Context UriInfo info)
The object ExtensionMetaDataRest is annotated with jackson
If have a JAX-RS application
public class MyJaxrsApplication extends JaxRsApplication implements InitializingBean, BeanFactoryAware {
@Autowired
@Qualifier("restletComponent")
public Component component;
@Autowired
public MyJaxrsApplication(final Context context) {
super(context);
}
public void afterPropertiesSet() throws Exception {
setContext(component.getContext().createChildContext());
add(new MyApplication());
getJaxRsRestlet().addClass(ServiceExceptionMapper.class);
getJaxRsRestlet().addClass(BaseExceptionMapper.class);
component.getDefaultHost().attach(this);
}
public void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
setObjectFactory(new ObjectFactory() {
public <T> T getInstance(Class<T> jaxRsClass) throws InstantiateException {
// Bean instantiation is delegated to spring
return beanFactory.getBean(jaxRsClass);
}
});
}
}
I start like this :
public void start() throws Exception {
LOGGER.info("Starting web component");
application.setDebugging(true);
restletComponent.getDefaultHost().attach(configService.getBaseUrl(), application);
restletComponent.start();
//following added to test if status service was used
final StatusService statusService = application.getStatusService();
if (!statusService.isEnabled()) {
statusService.setEnabled(true);
}
if (!statusService.isStarted()) {
statusService.stop();
}
proxyManager.configureProxy();
//Start proxy now
camelContext.start();
camelContext.startAllRoutes();
LOGGER.info("Web component started");
}
So I rely on ExceptionMapper to handle exception to response. This works fine most of the time, except when I have a JSON error. If the json is not well formatted, I'm expecting to go through the exception mapper, but instead I got a 400 Bad Request with the following content :
org.restlet.ext.jaxrs.internal.exceptions.ConvertRepresentationException: Could not convert the message body to a com.genesys.ucs.cs.model.ExtensionMetaDataRest
at org.restlet.ext.jaxrs.internal.exceptions.ConvertRepresentationException.object(ConvertRepresentationException.java:49)
at org.restlet.ext.jaxrs.internal.wrappers.params.EntityGetter.getValue(EntityGetter.java:107)
at org.restlet.ext.jaxrs.internal.wrappers.params.ParameterList.get(ParameterList.java:1123)
at org.restlet.ext.jaxrs.internal.wrappers.AbstractMethodWrapper.internalInvoke(AbstractMethodWrapper.java:160)
at org.restlet.ext.jaxrs.internal.wrappers.ResourceMethod.invoke(ResourceMethod.java:283)
at org.restlet.ext.jaxrs.JaxRsRestlet.invokeMethod(JaxRsRestlet.java:997)
at org.restlet.ext.jaxrs.JaxRsRestlet.handle(JaxRsRestlet.java:746)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:140)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:202)
at org.restlet.engine.application.ApplicationHelper.handle(ApplicationHelper.java:75)
at org.restlet.Application.handle(Application.java:385)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.routing.Router.doHandle(Router.java:422)
at org.restlet.routing.Router.handle(Router.java:639)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.routing.Router.doHandle(Router.java:422)
at org.restlet.routing.Router.handle(Router.java:639)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:140)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.routing.Filter.doHandle(Filter.java:150)
at org.restlet.routing.Filter.handle(Filter.java:197)
at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:202)
at org.restlet.Component.handle(Component.java:408)
at org.restlet.Server.handle(Server.java:507)
at org.restlet.engine.connector.ServerHelper.handle(ServerHelper.java:63)
at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:143)
at org.restlet.ext.jetty.JettyServerHelper$WrappedServer.handle(JettyServerHelper.java:273)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name
at [Source: HttpInputOverHTTP@2725f2e5; line: 2, column: 39] (through reference chain: com.genesys.ucs.cs.model.ExtensionMetaDataRest["attributes"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:189)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:249)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:206)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:238)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1269)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:864)
at org.restlet.ext.jackson.JacksonRepresentation.getObject(JacksonRepresentation.java:299)
at org.restlet.ext.jackson.JacksonConverter.toObject(JacksonConverter.java:208)
at org.restlet.service.ConverterService.toObject(ConverterService.java:229)
at org.restlet.ext.jaxrs.internal.provider.ConverterProvider.readFrom(ConverterProvider.java:144)
at org.restlet.ext.jaxrs.internal.wrappers.provider.SingletonProvider.readFrom(SingletonProvider.java:409)
at org.restlet.ext.jaxrs.internal.wrappers.params.EntityGetter.getValue(EntityGetter.java:101)
... 42 more
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name
at [Source: HttpInputOverHTTP@2725f2e5; line: 2, column: 39]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1419)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:508)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:437)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleOddName(UTF8StreamJsonParser.java:1799)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._parseName(UTF8StreamJsonParser.java:1496)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:693)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:231)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:232)
... 56 more
I don't understand why this is not handle through the exception mapper.
I tried to disable a status service, nothing changed. I tried to add my own, it wasn't used.
If error happens inside the resource, the exception mapper is called, but not during jackson conversion. I want to be able to customize the message sent back to user in case of json conversion error
After having a look at the code of the JAXRS extension, it appears that ConvertRepresentationException
s are directly wrapped into a JAXRS WebApplicationException
. The JaxRsProviders.convert
method should be used at this level but it's not. So you can't leverage JAXRS ExceptionHandler in this case.
See the content of the JaxRsRestlet#invokeMethod
and ExceptionHandler#convertRepresentationExc
methods for more details. It seems that the content of the JaxRsRestlet#handleInvocationTargetExc
method is what you expect as behavior.
I created an issue for this: https://github.com/restlet/restlet-framework-java/issues/1162.
Hope it heps you, Thierry