Reputation: 751
I have a class which takes enum values like Male,Female @POST . when I sent a wrong value like 'male' instead of 'Male' it shows me 400 Bad Request with this message in rest client : Can not construct instance of constants.Constants$GenderEnum from String value 'male': value not one of declared Enum instance names at [Source: org.apache.catalina.connector.CoyoteInputStream@718a453d; line: 7, column: 23] (through reference chain: valueobjects.ConsumerValueObject["gender"])
My Rest End Point Looks like below :
@Consumes("application/json")
@Produces("application/json")
@POST
public Response addConsumer(ConsumerValueObject consumerVO)
Here ConsumerValueObject holds the enum.
How to suppress that error message in Rest client? I tried with ExceptionMapper but it did not help!I need to suppress the message due to security issues!
Upvotes: 4
Views: 1428
Reputation: 208984
This is the Jackson response from either JsonParseExceptionMapper
or JsonMappingExceptionMapper
. These classes come with the dependency
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${2.x.version}</version>
</dependency>
Whether you have this explicit dependency or you have the resteasy-jackson2-provider (which uses the above under the hood), most likely the mappers are registered implicitly through classpath scanning. For instance you have an empty Application
class.
@ApplicationPath("/")
public class ResteasyApplication extends Application {}
This will cause disovery/registration through classpath scanning. If you don't have either of those dependencies, and if you are in Wildfly, I am not exactly sure how they are registered, but that is what's happening.
You could write/register your own ExceptionMappers
for the JsonParseException
and JsonMappingException
@Provider
public class JsonMappingExceptionMapper
implements ExceptionMapper<JsonMappingException> {
@Override
public Response toResponse(JsonMappingException e) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
}
but from what I have tested, it's a tossup as to which one will be registered, yours or Jackson's. The mappers are put into a Set (so unordered), then pushed into a Map, so only one get's pushed in. The order in which they are pushed in like I said is a tossup.
I guess this is really only a partial answer, as I have not been able to find a solution that is guaranteed to use your mapper, aside from registering all your classes explicitly (ultimately disabling the classpath scanning), but that is a hassle.
But now the fight has been narrowed down. I will try again some more if I get a chance later
So this is not a solution, just a semi-proof-of-concept to show how we can get it to use our ExceptionMapper.
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.my.pkg.JsonMappingExceptionMapper;
@Path("/init")
public class InitResource {
@GET
public Response init() {
ResteasyProviderFactory factory = ResteasyProviderFactory.getInstance();
factory.getExceptionMappers().put(JsonMappingException.class,
new JsonMappingExceptionMapper());
return Response.ok("Done!").build();
}
}
Once we hit the init
endpoint for first time, our JsonMappingExcpetionMapper
will register, and override the existing one, whether it is Jackson's or ours.
Of course we would not want to do this for real, it's just showing how to override the mapper. The thing I can't figure out is where to put this code. I've tried a ServletContextListener
, in the Application
constructor, in a Feature
with a low priority. I can't figure it out. None of the above occur before RESTeasy does its final registration.
Upvotes: 3
Reputation: 12839
Do you really want to supress the error message or do you want to fix the actual probelm?
You can actually catch all thrown exception with a custom exception mapper like
@Provider
public class CustomExceptionMapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Throwable t) {
return Response.ok().build();
}
}
though, this will handle all caught exceptions and return a 200 OK
which tricks clients to think that the request actually succeeded - which was not the case! Instead of Throwable
you should be able to catch the concrete exception (even if it is a RuntimeException) as well - maybe you have not declared it as provider or did not specify the correct exception class?
Though, as already mentioned returning a different status code for an exception is generally bad practice and should be avoided. Fixing the actual problem is probably more suitable in that case.
JAX-RS provides MessageBodyReader
and MessageBodyWriter
interfaces which you can declare to un/marshall an inputstream to an object or an object to return to an output-stream. The official documentation on MessageBodyReader has more detailed information on that regard.
One implementation therefore could be the following steps:
"male"
or "female"
tokens with their upper-case versionThis works if the input failure is just a simple upper/lower case issue. If there are typos or semantically alternative available, which are not yet in your enum, you need to put in a bit more effort.
If you, however, fail to create a proper object representation, you should return a user-failure (something in the 400 range) to the client to inform the client that something went wrong.
Upvotes: 1