8

How can I accept custom type query parameter?

public String detail(@QueryParam("request") final MYRequest request) {

Above line gives error while starting the server

jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Himanshu Yadav
  • 13,315
  • 46
  • 162
  • 291

1 Answers1

17

Take a look at the @QueryParam documentation, in regards to acceptable types to inject. (The same applies to all the other @XxxParam annotations also)

  1. Be a primitive type
  2. Have a constructor that accepts a single String argument
  3. Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String))
  4. Have a registered implementation of ParamConverterProvider JAX-RS extension SPI that returns a ParamConverter instance capable of a "from string" conversion for the type.
  5. Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2, 3 or 4 above. The resulting collection is read-only.

The reason for these requirements is that the value comes in as a string. The runtime needs to know how to convert a string to the type to inject. The reason for the exception is that there is an initial resource model validation on startup. This validation checks to make sure all your injection points are valid. It sees that the injected type MyRequest doesn't meet any of the above requirements, and throws an exception.

Basically you with points 2 and 3, you will need to parse the string yourself, for instance

public class MyRequest {
    public static MyRequest fromString(string param) {
        // 1. Parse string
        // 2. Create MyRequest request;
        return request;
    }
}

You can see a good example of using a ParamConverter here

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • What happens if I got a custom class with many member fields which has a constructor that accepts a single String which is just an empty constructor? will it still pass this class's object with its state? – CodeMonkey Sep 12 '16 at 07:55
  • @YonatanNir you need to construct the class yourself from just that string. Even if it means you need to manually parse the string. If you have something like a JSON structure as the string, take a look at the very last link in this post. It shows a third option. – Paul Samsotha Sep 12 '16 at 07:59
  • I understand I need to construct the class with the string which is the definition of having a String constructor. What I'm asking is what happens if I got other members in that custom class and my constructor is just a dummy empty constructor which accepts a String parameter.. will the values of the other members pass with the object? – CodeMonkey Sep 12 '16 at 08:06
  • By constructing I mean you need to set all the values youself. If you are using the constructor option (rather than the static valueOf), Jersey call's your constructor passing in the string parameter. It's your job to set the values of whatever members. – Paul Samsotha Sep 12 '16 at 08:16
  • @YonatanNir put it this way. A query parameter value is nothing but a String. Jersey has no idea how to create your custom types from that string. But it gives you some rules you can follow that will allow Jersey to pass you the string, and you do whatever you want with it to create the object – Paul Samsotha Sep 12 '16 at 08:20
  • This doesn't seem to work. I had an exception before adding to fromString method and after ive added it was gone but the method is not called – CodeMonkey Sep 13 '16 at 07:22
  • @YonatanNir Make sure it's static. Other than that, if you want to update your post (the one I closed as a dup) with the code, I'll reopen it. Just let me know once/if you do. – Paul Samsotha Sep 13 '16 at 07:44
  • It is static. Please look here: http://stackoverflow.com/questions/39464786/jersey-objects-tostring-method-is-not-called – CodeMonkey Sep 13 '16 at 07:51
  • What do you throw if you cannot convert `param` to `MyRequest`? `IllegalArgumentException` or `BadRequestException`? Does it even matter? – Robin Jonsson Jul 11 '17 at 14:02
  • @RobinJonsson personally I don't like throwing JAX-RS exceptions in things like this. It's really bad design IMO, and it kills any chance of reuse outside of JAX-RS. If you _do_ throw a JAX-RS exception, then you can control what get's back to the client. If you just throw a normal exception, then you have to take the default behavior for JAX-RS, which is always 404 for any `@QueryParam` or `@PathParam`, and 400 for `@FormParam`. If you want something different, it might be preferable to implement a ParamConverterProvider. You just catch and (re)throw a JAX-RS exception there – Paul Samsotha Jul 11 '17 at 14:10
  • Well we are going to use a special class used only for `@XxxParam` values. Just figured out that throwing `IllegalArgumentException` causes a 404 Not Found. Throwing `BadRequestException` gives you the expected 400 – Robin Jonsson Jul 11 '17 at 17:21