0

Suppose, we have 2 RESTful webservices (JAX-RS). The first service acts as a consumer and calls the API of the second service. The second service (provider) is generated using the openapi-generator-maven-plugin with jaxrs-spec option and an underlying .yml-file describing the API. Both the provider- and the consumer webservices are deployed successfully on the Weblogic application server and serve requests as expected...

... with one little exception. The serialization / deserialization of Enums is not working as expected. Eums are generated with the corresponding Jackson2 Annotations @JsonValue and @Jsoncreator:

public enum MyEnum {
   FIRST_VALUE("first_value"),
   SECOND_VALUE("second_value");

   private static Map<String, MyEnum> ENUM_MAP = Stream
        .of(MyEnum.values())
        .collect(Collectors.toMap(s -> s.formatted, Function.identity()));

   private final String value;

   private MyEnum(String value) { this.value = value; }

   @JsonValue 
   public String value() { return value; }

   @JsonCreator
   public static MyEnum fromString(String string) {
        return Optional
            .ofNullable(ENUM_MAP.get(string))
            .orElseThrow(() -> new IllegalArgumentException(string));
    }

}

The expectation would be (assuming the Jackson annotations would not be ignored by the ObjectMapper) that a Java object MyEnum.FIRST_VALUE gets serialized as {"first_value"}. However, the result (what the provider webservice receives and the consumer webservice sends) is {"FIRST_VALUE"}. How come? Weblogic uses MOXy as default JSON provider. And MOXy ignores the above mentioned Jackson2 Annotations.

The question, therefore is: How can I make the webservice receive {"first_value"} instead of {"FIRST_VALUE"} and how am I supposed to adjust my JAX-RS Jersey Client (in the first webservice) in order to pass the value {"first_value"} to my second webservice when called using

Client client = ClientBuilder().newClient();
client.target(MY_URI)
      .request(MediaType.APPLICATION_JSON)
      .post(Entity.entity(MyEnum.FIRST_VALUE, MediaType.APPLICATION_JSON));

I tried the following:

  1. Finding out that serialization / deserialization works correctly in a Java SE environment when we use Jackson as JSON provider (after adding the corresponding maven coordinates). Please click here, my example Enum looks the same (plus @JsonValue Annotation, minus @JsonProperty). However, serialization works as expected in a Java SE Unit-Test
  2. Finding out that MOXy needs JAXB-Annotations, so we could use the openapi-generator-maven-plugin to generate JAXB-Annotations. See here. Seems a little too complicated to achieve the goal.
  3. Writing a custom XmlAdapter, see here. Why would we do that, when Jackson does the marshalling out of the box?
  4. Disable MOXy as default JSON provider, see here. Actually, this solves the problem on the producer side, but what about the consumer? The client still sends the "wrong" JSON, so that the service throws an Exception.
tim-danger
  • 11
  • 4

1 Answers1

0

I was finally able to solve the problem. Hopefully this will be helpful to some poor soul struggling with the same problem. As I have already pointed out in my original question, the solution is to disable MOXy:

Provider:

import javax.ws.rs.core.Application;
public class MyApplication extends Application
{
    @Override
    public Map<String, Object> getProperties()
    {
        Map<String, Object> proprties = new HashMap<>();
        proprties.put("jersey.config.server.disableMoxyJson", true);

        return proprties;
    }
}

See also Weblogic 12.2.1.3 from Moxy to Jackson

Consumer:

javax.ws.rs.client.ClientBuilder.newClient().register(Class.forName("org.glassfish.jersey.jackson.JacksonFeature"));

This will do the trick on the client side.

See also Weblogic 12.2.1.2 - How to tune the object Serializer to use Jackson 2 and strange phenomena on jaxrs enablement for application/json endpoints

Kudos to 99Sono. Thank you so much for ending this odyssey!

tim-danger
  • 11
  • 4