简体   繁体   中英

Java JSON Mapping of List size 1

I am mapping an object to JSON and have a problem with one variable called Parameters of type List <SimilarityParameter> .

SimilarityParameter looks like this:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class SimilarityParameter {

    private String name;
    private String type;

    public SimilarityParameter() {

    }

    public SimilarityParameter(String name, String type) {
        this.name = name;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

When this List is large everything is OK. The JSON looks like this

{
  "parameters":[
    {
      "name":"threshold",
      "type":"Double"
    },
    {
      "name":"numberOfResults",
      "type":"Integer"
    }
  ]
}

This is OK because after JSON encoding on the client side I have an array of Parameters.

The problem is when List is of size 1. Mapper transfers it logically to:

{
  "parameters":{
    "name":"numberOfResults",
    "type":"Integer"
  }
}

When the client decodes this JSON gets gets an array containing name and type . It causes inconsistencies on the client side.

I would like to map List of size 1 to this:

{
  "parameters":[
    {
      "name":"threshold",
      "type":"Double"
    }
  ]
}

So after encoding array containing one parameter.

This is how the response looks:

@XmlRootElement(name = "availableSimilarities")
@XmlAccessorType(XmlAccessType.FIELD)
public class SimilarityInfoResult {

    private String similarityName;
    private List <SimilarityParameter> parameters;

    public SimilarityInfoResult() {

    }

    public SimilarityInfoResult(String similarityName, List<SimilarityParameter> parameters) {
        this.similarityName = similarityName;
        this.parameters = parameters; 
    }

    public String getName() {
        return similarityName;
    }

    public void setName(String similarityName) {
        this.similarityName = similarityName;
    }

    public List<SimilarityParameter> getParameters() {
        return parameters;
    }

    public void setParameters(List<SimilarityParameter> parameters) {
        this.parameters = parameters;
    }


}

Is it possible to achieve this?

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

The problem is when List is of size 1. Mapper transfers it logically to:

The JAXB specification itself does not cover JSON-binding so sometimes implementations are used with libraries like Jettison which converts XML events to/from JSON and problems occur such as collections of size 1 being represented incorrectly. This is because Jettison (and similar) libraries can only detect collections when they see an element appear more than once.


Is it possible to achieve this?

The EclipseLink MOXy implementation of JAXB offers native JSON binding meaning that items like collections of size 1 will be properly converted to JSON.

jaxb.properties

To specify MOXy as your JAXB provider you need to include a file called jaxb.properites in the same package as your domain model with the following entry:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo

import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(2);
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {SimilarityInfoResult.class}, properties);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource json = new StreamSource("src/forum15316288/input.json");
        SimilarityInfoResult result = unmarshaller.unmarshal(json, SimilarityInfoResult.class).getValue();

        Marshaller marshaller= jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(result, System.out);
    }

}

input.json/Output

{
   "parameters" : [ {
      "name" : "threshold",
      "type" : "Double"
   } ]
}

For More Information

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM