0

I'd like a endpoint to accept on a single verb and path a json payload that varies by a tiny bit and that can be mapped to different objects. The variation is usually on the field value like the grant_type in the OAuth world.

I scrapped stackoverflow and google on this, I found this among other

But those question don't seem to be relevant to me, jackson deserialisation alone works fine for this payloads, but Jersey always refuses to init the servlet with an error that let me thinks there's no way around it.

@Path("parent")
interface Resource {
    @POST
    @Path("test")
    String test(Payload1 payload1);

    @POST
    @Path("test")
    String test(Payload2 payload1);

    @Data
    @JsonTypeName("payload1")
    class Payload1 extends BasePayload {
        String a;
    }

    @Data
    @JsonTypeName("payload2")
    class Payload2 extends BasePayload {
        String b;
    }

//    @JsonTypeInfo(use= Id.MINIMAL_CLASS, include=As.PROPERTY, property="@class")
    @JsonTypeInfo(use= Id.NAME, include=As.PROPERTY, property="@payload")
    @JsonSubTypes({
                      @JsonSubTypes.Type(value = Payload1.class),
                      @JsonSubTypes.Type(value = Payload2.class)
    })
    class BasePayload {
    }

However I get this message in an exception upon servlet initialisation. (edited message for clarity)

</pre><p><b>root cause</b></p><pre>
org.glassfish.jersey.server.model.ModelValidationException: 
  Validation of the application resource model has failed during application initialization.

[[FATAL] A resource model has 
ambiguous (sub-)resource method for HTTP method POST and input mime-types as defined by
 "@Consumes" and "@Produces" annotations 
at Java methods 
 public java.lang.String xxx.Service.test(xxx.Resource$Payload1) 
and 
 public java.lang.String xxx.Service.test(xxx.Resource$Payload2) 
at matching regular expression /test. 

These two methods produces and consumes exactly the same mime-types and 
therefore their invocation as a resource methods will always fail.;
source='org.glassfish.jersey.server.model.RuntimeResource@59b668bf']

Note however that having a endpoint with the parent class of the payload works, but you have to handle the dispatch yourself.

@POST
@Path("test")
String test(BasePayload payload);

I'm using Spring-Boot 1.4 / Jersey 2.23.2 / Jackson 2.8.5

bric3
  • 40,072
  • 9
  • 91
  • 111

1 Answers1

1

The JAX-RS runtime uses the following for matching requests to resource methods:

  • URI: Defined in the @Path annotation.

  • Request method: Defined by a resource method designator such as @GET, @POST, etc).

  • Media type: Defined in Accept and Content-Type headers, that are matched with the values defined in the @Produces and @Consumes annotations, respectively.

The content of the payload is not taken into account, so it makes your first method definition ambiguous.

As you already figured out, the following approach is the way to go:

@POST
@Path("test")
String test(BasePayload payload);
Community
  • 1
  • 1
cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • I understand that it can make the resource discovery ambiguous, but I wonder if there is some configuration or tweaks in Jersey that can remove this ambiguity by leveraging the deserialisation performed by jackson. – bric3 Sep 22 '17 at 16:35
  • By the way I also tried to return a sub-resource doing the logic (as in [this answer](https://stackoverflow.com/questions/28946704/use-header-in-addition-to-method-to-route-request-to-annotated-method)), but jersey wants to serialise the sub-resource... – bric3 Sep 22 '17 at 17:30
  • I just read the point §3.7 of the [jax rs specification](http://download.oracle.com/otn-pub/jcp/jaxrs-2_0-fr-eval-spec/jsr339-jaxrs-2.0-final-spec.pdf?AuthParam=1506414647_27ffa6d21eb901f213b2c8d27807a92b). However note that the spec let implementors can deal in an implementation-specific way this _ambiguity_. I just thought that Jersey was a tad more clever than the spec in stead of following it rigorously. But there's many holes in this regard too (injection for example has been buggy for years). – bric3 Sep 26 '17 at 13:10
  • @Brice Once Jersey is the reference implementation of JAX-RS, I think it definitely should following it rigorously. I've tried different approaches over the past few days and haven't succeeded. – cassiomolin Sep 26 '17 at 13:17
  • Actually one thing that I didn't mention is the use of `@PreMatching` to _route_ calls to different resources. I've used it in the past to implements OAuth2 endpoint in JAX-RS, however I had to actually perform the deserialisation myself of the form params. But the specification is very clear that at some point the implementors have their own behaviour, I hoped that Jersey would not back out entirely in this case. – bric3 Sep 26 '17 at 14:04