Reputation: 8936
I defined a datatype and its API:
public class DataType {
@Column
private String name;
}
// API is:
public class DataTypeAPI {
@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ManagedAsync
public void createDataType(
final DataType dataType,
) {
...
asyncResponse.resume(Response.status(Response.Status.CREATED)
.entity(dataType)
.build());
}
}
Everything is fine if I posed
{
"name": "xxx"
}
,
but when I posted { "name1": "xxx" }
, I got the following text/plain
response:
Unrecognized field "name1" (class com.xxx.datatypes.DataType), not marked as ignorable (1 known properties: "name"])
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@526e34b1; line: 2, column: 15] (through reference chain: com.xxx.datatypes.DataType["name1"])
I prefer to convert the above error into JSON response. but event I added the following exception mapper, it is not returning JSON response.
@Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
public Response toResponse(Throwable ex) {
System.out.println("GenericExceptionMapper");
ex.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorBody(500, ex.getMessage()))
.type(MediaType.APPLICATION_JSON)
.build();
}
}
Why my above exception mapper cannot catch the jersey parsing error. Could someone explain it to me? Thanks
UPDATE
I have two questions:
1, how to make the response to be application/json
instead of text/plain
?
2, why my exception mapper did not catch the exception raised and map it to a json response?
UPDATE
I added the following mapper:
public class JsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {
public Response toResponse(JsonMappingException ex) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorBody(500, ex.getMessage()))
.type(MediaType.APPLICATION_JSON)
.build();
}
}
Now, I can get the json response:
{
"code": 500,
"message": "Unrecognized field \"name1\" (class com.xxx.datatypes.DataType), not marked as ignorable (1 known properties: \"name\"])\n at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@1d8cd12a; line: 2, column: 15] (through reference chain: class com.xxx.datatypes.DataType[\"name1\"])"
}
I still have two questions:
1, why my generic exception mapper cannot catch it.
2, The json mapping exception mapper cannot map the following exception Unexpected character ('}' (code 125)): was expecting double-quote to start field name
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@7615743c; line: 3, column: 2]
when {"name": "xxxx",}
posted (comma , added for testing)
Upvotes: 7
Views: 9655
Reputation: 1104
Im using org.glassfish.jersey-jackson-2.33. when you register JacksonFeature which is responsible for the default Jackson response with a "withoutExceptionMappers())". then if you have some Throwable exception mapper it will be catch instead of the default jackson mapper. you can also write your JsonParseException mapper if you dont use a Throwable mapper.
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
public class JerseyApplication extends ResourceConfig {
//register(JacksonFeature.class);
register(JacksonFeature.withoutExceptionMappers());
}
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.core.JsonParseException;
@Provider
public class JsonExceptionsMapper implements ExceptionMapper<JsonParseException> {
@Override
public Response toResponse(JsonParseException exception) {
//replace with your custom response
return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()).type("text/plain").build();
}
}
Upvotes: 0
Reputation: 793
I met the same issue, and I have solved it. I try to explain your question:
Both JsonMappingException
and JsonParseException
extend JsonProcessingException
. And Jersey has defined JsonMappingExceptionMapper
for JsonMappingException
and JsonParseExceptionMapper
for JsonParseException
.
JsonProcessingException
(or more wide exception mapper), it cannot catch JsonMappingException
and JsonParseException
, because these two exceptions have their own mapper. If they have not, your mapper can catch.XxxJsonMappingExceptionMapper
for JsonMappingException
and YyyJsonParseExceptionMapper
for JsonParseException
), you may find sometimes you can catch these exceptions, sometimes cannot, it depends your own mapper is working or jersey's mapper is working. Now, you can add @Priority(1)
(javax.annotation.Priority) to your mapper to make sure your mapper is working. see Jackson JsonParseExceptionMapper and JsonMappingExceptionMapper shadows custom mapper.back to your question:
JsonMappingExceptionMapper
and JsonParseExceptionMapper
, they have a higher priority).JsonParseExceptionMapper
. Try to figure out by adding @Priority(1)
to your own mapperUpvotes: 5
Reputation: 208984
why my generic exception mapper cannot catch it.
Because the Jackson-JAXRS module already comes with ExceptionMappers for Jackson exceptions.
The json mapping exception mapper cannot map the following exception
I didn't test this, but it most likely because it is not a mapping exception, but a parsing exception. Jackson has both JsonParseException
and JsonMappingException
. You can see in the previous link that Jackson comes with an ExceptionMapper for both JsonMappingException
and JsonParseException
. You are only overriding the mapper for JsonMappingException
.
Upvotes: 1
Reputation: 31397
Unrecognized field "name1" (class com.xxx.datatypes.DataType), not marked as ignorable (1 known properties: "name"])
If you look at the exception raised, it is quite clear that, your POJO class has property with name name
not name1
.
And, you are trying to post your JSON with property name name1
.
{ "name1": "xxx" }
And, it wasn't recognized as name1
wasn't defined instead name
.
public class DataType {
@Column
private String name;
}
And that is the reason , it works fine for you in other case, when you post JSON as
{ "name": "xxx" }
Upvotes: 0