How to validate a single parameter in DropWizard - java

I want to validate some input parameters in DropWizard as documented here: https://dropwizard.github.io/dropwizard/manual/core.html#validation
This example validates an object's properties, which works fine, but my service doesn't receive an object, but the parameters directly. This is a simplification of my code:
#GET
#Path("/MyResource/{myresourceId}")
public MyResource detail(#PathParam("myresourceId") #Valid #Size(min = 2, max = 5) String myresourceId) {
The #Valid and #Size annotations seem to be ignored in this case.
Anyone knows if this is possible and if so how to do it right? Thanks.

It's not possible with those annotations as method parameters. Have a look at this thread.
You might be able to write some AOP code to support this (depending on how you're initializing your resources).

Related

org.springframework.web.bind.MethodArgumentNotValidException

I am using spring boot and I have a RestController with method
addBook(#Validated #RequestBody BookDto bookDto)
BookDto has a field annotated with write only
#JsonProperty(access = Access.WRITE_ONLY)
#NotNull(message = "cannot be empty")
#Size(min = 1, max = 20)
private String isdnNo;
This works as expected and I have to provide isdnNo while i do a post request.
And when I get it don't bring the isdnNo in reponse which is fine.
Issue here is in JUnit test case. I am using stand alone setup to test controller.
MockMvcBuilders.standaloneSetup(bookController).build();
MockHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.post("/books/").contentType(JSON)
.accept(JSON);
postRequest.content(asJsonString(bookDto));
ResultActions result = mvc.perform(postRequest);
This JUnit test case gives exception org.springframework.web.bind.MethodArgumentNotValidException and says idnNo cannot be empty even though I have provided isdnNo in bookDto on performing post. What can be the issue here.
if I remove #JsonProperty(access = Access.WRITE_ONLY) the test case works fine.
Thanks in advance !
You want to keep Access.WRITE_ONLY removed because, according to the documentation, during serialization (ie writing it to a string) it will not read the value for serialization. You're method asJsonString is serializing the object thus removing the value.
AUTO: Access setting which means that visibility rules are to be used to automatically determine read- and/or write-access of this property.
READ_ONLY:
Access setting that means that the property may only be read for serialization, but not written (set) during deserialization.
READ_WRITE
Access setting that means that the property will be accessed for both serialization (writing out values as external representation) and deserialization (reading values from external representation), regardless of visibility rules.
WRITE_ONLY
Access setting that means that the property may only be written (set) for deserialization, but will not be read (get) on serialization, that is, the value of the property is not included in serialization.
https://fasterxml.github.io/jackson-annotations/javadoc/2.6/index.html?com/fasterxml/jackson/annotation/JsonProperty.Access.html

I cannot get to the correct #Path

Using JAX-RS, I have the following 3 #Paths.
#Path(JobRest.PATH)
#Api(value = JobRest.PATH, description = "REST APIs for Jobs")
public interface JobRest {
public static final String PATH = "/job";
#GET
#Path("/last")
#Produces(MediaType.APPLICATION_JSON)
public Job retrieveLastJob(...);
#GET
#Path("/{jobId}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Job retrieveJob(...., #PathParam("jobId") String jobId, );
#GET
#Produces(MediaType.APPLICATION_JSON)
public JobList retrieveAllJobs(....);
}
/job correctly calls retrieveAllJobs()
/job/1236 correctly calls retrieveJob(..., "1236", ...).
I expected that /job/last would call retrieveLastJob(...), since it matches, but it calls retrieveJob(..., "last", ...) instead.
How do I change the notation so that /job/last will call retrieveLastJob(...)?
TL;DR
Remove the #Consumes(MediaType.APPLICATION_JSON) on the retrieveJob method. For one, it does not accept a body, so it does not consume anything. Secondly it conflicts with the expected behavior.
I've tested with both Jersey and RESTeasy and it seems to be a difference in implementation. Jersey works fine with your code, while RESTeasy always hits the retrieveJob method, as you are experiencing.
Here's my take. If you look at the JAX-RS spec; 3.7.2 Request Matching, there's a semi-cryptic algorithm for matching resources, that goes something like this.
Get all matching resource class (by path), put them into a set.
Get all matching resource methods (by path), put them into a set.
Sort the methods by best matching path (most literal characters go first).
Sort by media type (with consumes and produces).
From my perspective, in this particular case, after step 3, the retrieveLastJob should automatically win, as it has the most literal characters. The producing media types are the same, and the consumes media type should not even matter, since it is a GET request with no Content-Type to do any matching.
My guess it RESTeasy still uses the annotation to sort even though it should not even be taken into consideration in this case. So it would appear that the method with the annotation is given more precedence, as it appears to be more specific, by way of just having an annotation, while the other does not. But that (step 4) level of specificity really shouldn't matter in this case.
I don't know if it's a bug against the spec. It's not too clear on how it should be handled, but I personally think the Jersey behavior is the correct behavior, for the simple fact that this level of specificity should not matter in this particular case. In any case, it is not correct to have the #Consumes annotation anyway for a GET request with no body.

Bean Validation - constructor/factory parameter

I have a dto object which keeps an IP Range using first and last fields. Simple CRUD operations are made with this class using dropwizard (jersey-jackson-hibernate validator)
public class IpRangeDto {
#JsonCreator
public static IpRangeDto fromCidr(#JsonProperty("cidr") String cidr) {
//Resolve CIDR and assign first and last fields
}
#NotNull
#IpAddress // My custom validator
private String first;
#NotNull
#IpAddress
private String last;
}
For the sake of user-friendliness I had decided to add an alternative way to create this object, which is by using CIDR. So the client could send either first and last fields in JSON or only the cidr field. So the way to do it is as above, using #JsonCreator. And it works just fine.
"ipRange":{
"first": "15.0.0.1",
"last": "15.0.0.255",
}
"ipRange":{
"cidr": "15.0.0.0/24"
}
I want to validate this CIDR value that it's the right format so I can return 422 with proper error message. If I throw exception in the constructor/factory method then jersey-jackson returns 400 directly (even if I throw ConstraintViolationException, it's encapsulated by JsonProcessingException).
I could simply ignore the exceptions, and leave the fields empty which will return 422 because of #NotNull constraints but then the error message will not be as clear as it should be.
I tried adding my #Cidr validator next to the #JsonProperty parameter but that doesn't seem to be effective. My understanding is that validation occurs after Jackson is finished with creating Dtos, so with my #JsonCreator approach there might not be any solution to this problem. So I'm open to refactoring suggestions as well.
I am not an expert on the exact integration of Bean Validation into jackson, but I think it is just doing actual property validation. This means as you already pointed out, the entities are created first and then the properties are validated.
Bean Validation (as of version 1.1) also offers so called method validation, in which case you could place your Cidr constraint onto the string parameter of the method, but as said, I don't think that there is an integration in jackson for that.
And one more thing ;-) - static methods and properties are generally excluded from validation in Bean Validation (see also http://beanvalidation.org/1.1/spec/#d0e2815).
Regarding a workaround, one thing comes to mind (even though it feels a bit complicated). Write a custom class level IpRange constraint. In a class constraint you would get passed a IpRangeDto instance and it is up to you to validate the whole object and select the right error message for any violations. Provided you would add a cidr property to the dto which gets set when fromCidr is called, you would have then all information you need for the validation and selection of a proper error message.

Jackson - Required property?

I'm using Jackson's readValue() method on an object mapper to read from a JSON file and convert it into my java object.
eg.
mapperObject.readValue( node, MyTargetClass.class )
Are there any annotations that I can set on MyTargetClass to enforce required attributes? For example, if I have a JSON object with properties ABC,DEF and GHI, and my Json is the following
{
"ABC" : "somevalue"
"DEF" : "someothervalue"
}
I want it to fail somehow, and only succeed on the readValue if it contained ABC, DEF and GHI.
You can mark a property as required with the #JsonProperty(required = true) annotation, and it will throw a JsonMappingException during deserialization if the property is missing or null.
Edit: I received a downvote for this without comment. I'd love to know why, since it does exactly the right thing.
Jackson does not include validation functionality, and this is by design (i.e. that is considered out-of-scope). But what is usually used is Bean Validation API implementation.
The nice thing about this is decoupling between data format handling, and validation logic.
This is what frameworks like DropWizard use; and it's the direction JAX-RS (like Jersey) are taking things for JAX-RS 2.0.
If you want to make sure a json field is provided, you have to use the #JsonProperty(value = "fieldName", required = true) annotation as a parameter to the constructor. But this is not enough, also the Constructor should have #JsonCreator annotation.
For example, if you have a field named 'endPoint' and you want o make sure it is provided in the JSON file, then the following code will throw an exception if it is not provided.
#JsonCreator
public QuerySettings(#JsonProperty(value = "endPoint", required = true) String endPoint) {
this.endPoint = endPoint;
}
I found this link helpful to understand the Jackson annotations. It also well explains why required=true is not enough and counter-intuitive to its name.
If you are neither satisfied with using #JsonProperty(required = true) as it works only with #JsonCreator nor with the use of bean validation then one more way of tackling it would be to catch this in your setter methods for the relevant variables.
You can simply check if the variable is null before setting it and throw an IllegalArgumentException or NullPointerException (as preferred by few people)
Note: It depends on how your POJO is defined too, so please make sure that it is going the setter method route for this solution to work.

Escaping specific strings in spring-mvc

I'm using spring MVC (spring 3.1.0).
I would like to html encode every string output from my system due to XSS.
But there are outputs (like links) that I don't want to encode in that manner - in order to do that I've decided to use ContextualSerializer and create a class that implements it.
The method createContextual checks for existence of a custom annotation (#NoHTMLEscap) and determine the JsonSerializer to return.
Here is my annotation:
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotation
public #interface NoHTMLEscap {
}
I tried it and it works just great - on POJOs, but here is a case that fails:
#Controller
#RequestMapping(value = "/something")
public class MyController {
...
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
#ResponseBody
#ResponseStatus(value = HttpStatus.OK)
public String getName(#PathVariable String id) {
return "Here is your answer";
}
}
Spring sends to jackson the returned value and since this method returns String and not POJO - there is no way to check the existence of my annotation - so I cannot actually use my annotation there...
Is there a way to get this information to Jackson's serializer?
I'm not sure but I thought that maybe I need to use a spring specific converter which will never escape strings (not really sure if this will solve correctly my issue and how this can be implemented)?
I don't think jackson can provide a straightforward actual solution for your use-case but I can suggest a different solution.
If you can afford to have a wrapper object around these Strings, let's say LinkWrapper, you can add another serializer of LinkWrapper which will just delegate to your current serializer. In your LinkWrapper object you will annotate the String with your annotation and so your delegated serializer will serialize it unencoded.
Also your output won't be that of an object since your custom serializer only delegates to that of a string serializer.
If you need a code sample just say but I think it's a really simple case of composition.

Categories