0

This is similar to my post here...

JAXB Unmarshal JSON HTTP POST Parameters

Except in this case I need to unmarshal my JSON that not only contains the HTTP POST parameters but also an object. Consider the following JSON...

{
  "client": "1",
  "forTopic": "topic",
  "MyObject":{
    "name":"the name",
    "id":1
  }
}

client and forTopic are the HTTP POST parameters. MyObject is the object I'm trying to receive to act on. I'd like to pull the parameters separately from the object.

I can do this by setting up an object that contains 3 fields. Field 1 is a String for client. Field 2 is an int for id. Field 3 is MyObject theObject.

This allows me to pull everything fine. However I'd prefer not to have to create a "wrapper" class for each of my objects that has parameters. Is there a better/proper way to do this? Either by pulling the parameters out of the JSON and be left with the resulting JSON of MyObject to then unmarshal or somehow specify the depth to dig down into the JSON to unmarshal? The parameters are fairly consistent for each of my objects. I just don't want to have to create wrappers fo them all.

Perhaps another way to ask this is what is the proper approach to handle HTTP POST parameters contained in your JSON using JAXB/Moxy?

Edit :

For reference. Here are my relevant dependencies.

    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.moxy</artifactId>
        <version>2.7.2</version>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>

And my jaxb.properties...

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Etep
  • 533
  • 7
  • 20
  • .JAXB is for unmarshalling **XML**, not for unmarshalling **JSON**. – Thomas Fritsch Sep 26 '18 at 19:37
  • @ThomasFritsch JAXB can unmarshal JSON with added technology such as Moxy as I mention in my post. Please see my link in my original post or have a look here... https://stackoverflow.com/questions/38789307/how-to-serialize-jaxb-object-to-json-with-jaxb-reference-implementation – Etep Sep 26 '18 at 23:22

1 Answers1

2

Personally I would use a wrapper object but there are ways to do what you want. I created a small spring boot app to check your scenario.

First let's create a pojo for MyObject that makes use of jaxb:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MyObject {
    @XmlElement(name = "id")
    private String id_blah;

    @XmlElement(name = "name")
    private String Name;

    public String getId_blah() {
        return id_blah;
    }

    public void setId_blah(String id_blah) {
        this.id_blah = id_blah;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }
}

We will create a custom deserializer for handling the incoming payload:

public class MyObjectDeserializer extends StdDeserializer<MyObject> {


        public MyObjectDeserializer() {
            this(null);
        }

        public MyObjectDeserializer(Class<?> vc) {
            super(vc);
        }

        @Override
        public MyObject deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {

            JsonNode jsonPayload = jp.getCodec().readTree(jp);
            JsonNode myObjectNode = jsonPayload.get("MyObject");
            MyObject myObject = new MyObject();
            myObject.setId_blah(myObjectNode.get("id").textValue());
            myObject.setName(myObjectNode.get("name").textValue());
            return myObject;
        }
    }

We will register our deserializer into the message converters:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }


    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);

        ObjectMapper objectMapper = new ObjectMapper();
        MappingJackson2HttpMessageConverter jaxMsgConverter = new MappingJackson2HttpMessageConverter();
        AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
        objectMapper.setAnnotationIntrospector(introspector);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        SimpleModule module = new SimpleModule();
        module.addDeserializer(MyObject.class, new MyObjectDeserializer());
        objectMapper.registerModule(module);
        jaxMsgConverter.setObjectMapper(objectMapper);
        converters.add(jaxMsgConverter);
    }
}

And an endpoint to test that everything works fine:

@RestController
public class Controller {

    @PostMapping("/test")
    public String test(@RequestBody MyObject myObject) {
        return myObject.getName();
    }
}

Posting the json in your question works fine.

The dependencies for my sample-project:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.2.11</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-jaxb-annotations</artifactId>
            <version>2.9.6</version>
        </dependency>
    </dependencies>
martidis
  • 2,897
  • 1
  • 11
  • 13
  • Wow! Very detailed and concise. Thank you for this. One question I have is can this be done without Jackson? I haven't delved into Jackson as of yet, looks like perhaps I should to further streamline my REST API? I'll dig into Moxy further to see if I can added these converters without having to go the Jackson route. Looks very similar to how xstream works with registering a custom converter. – Etep Sep 27 '18 at 15:57
  • 1
    Hi @Etep. To be honest I am not familiar with Moxy. When possible I check it out and come back to you – martidis Sep 28 '18 at 06:01