복붙노트

[SPRING] 잭슨을 사용하여 자바에 POJO로 JSON 변환하는 방법

SPRING

잭슨을 사용하여 자바에 POJO로 JSON 변환하는 방법

나는 봄 3.1.2를 사용하고 있는데 나는 POJO로 JSON 개체를 구문 분석 할 필요가있다. 이것은 내가 구문 분석하는 데 필요한 JSON입니다 :

{
"Person" : {
    "id" : "2"
 },
"Dog" : {
    "dateOfBirth" : "2012-08-20 00:00:00",
    "price" : "10.00"
    }
}

내가 한 POJO로 (두 객체에서 결합)이 JSON 객체로 변환 할 필요가 여기있다 :

public class MyClass{
     public MyClass(){}
     public MyClass(String personsId, TimeStamp dogsDateOfBirth, BigDecimal dogsPrice){
     .... // assign each parameter to the appropriate field
     }
     private String personsId;
     private TimeStamp dogsDateOfBirth;
     private BigDecimal dogsPrice;
     //... Getters and Setters for each field
}

그 문제에 내가 ObjectMapper 매퍼 = 새로운 ObjectMapper를 사용 (); 이제이 있기 때문에 여러 JSON 내 코드는 다음과 같습니다 객체 :

    String json = ... ;// A json with several objects as above
    JsonNode tree = mapper.readTree(json);
    Iterator<JsonNode> iter = tree.path("data").getElements();
    while (iter.hasNext()){
        JsonNode node = iter.next();
        MyClass myClass = mapper.readValue(node, MyClass.class);
        ... // do something with myClass object
    }

나는이 프로그램을 실행할 때 - 나는 다음과 같은 예외를 얻을 :

org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class ...MyClass]: can not instantiate from JSON object (need to add/enable type information?)

나는 간단한 POJO를 만들려고 - 사람을 :

public class Person{
        private String id;          
        public Person(){}
        public Person(String id){
            this.id = id;
         }
         ... // Getter and Setter
    }

다음을 수행 :

Person person = mapper.readValue(node.path("Person"), Person.class);

나는이 (같은) 예외를 얻을 :

org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class ...Person]: can not instantiate from JSON object (need to add/enable type information?)

나는 형식 정보에 대한 몇 가지를 읽으려고 -하지만 여기에 나를 도울 수있는 방법을 이해할 수 없었다.

어떻게 POJO에이 JSON을 변환 할 수 있습니까?

감사.

해결법

  1. ==============================

    1.내가 한 일은이 있었다 : 나는 Person 객체와 개 개체를 보유 새로운 클래스, 이러한 클래스는 (내가 여기 있음) 고정 할 필요가 만들었습니다. 여기에 클래스는 다음과 같습니다

    내가 한 일은이 있었다 : 나는 Person 객체와 개 개체를 보유 새로운 클래스, 이러한 클래스는 (내가 여기 있음) 고정 할 필요가 만들었습니다. 여기에 클래스는 다음과 같습니다

    public static class MyNewClass{
        private Person person;
        private Dog dog;
        ... // two constructors and getters and setters
    
     public static class Person{
         private String id;
         ... // two constructors and getters and setters
     }
     public static class Dog{
         private String dateOfBirth;
         private String price;
         ... // two constructors and getters and setters
      }
    }
    

    이제 내 코드는 다음과 같습니다 :

        JsonNode tree = mapper.readTree(jsonString);
        Iterator<JsonNode> iter = tree.path("data").getElements();
        while (iter.hasNext()){
            JsonNode node = iter.next();
            Person person = mapper.readValue(node.path("Person"), Person.class);
            Dog dog = mapper.readValue(node.path("Dog"), Dog.class);
            MyNewClass myNewClass = new MyNewClass(person , dog);
            ... //Do something with it
        }
    

    지금은 충분히 That'a 좋은 - - 나는 아직도이 두 개체 (사람과 개를) 만들지 않고 그것을 할 싶어하지만 누군가가 생각이있는 경우 - 여기 싶습니다!

    감사.

  2. ==============================

    2.잭슨 오류 : 문제는 여기에 설명과 동일하지 않습니다 더 적합한 생성자

    잭슨 오류 : 문제는 여기에 설명과 동일하지 않습니다 더 적합한 생성자

    인스턴스화하려는 클래스는 정적 없습니다. 그 때문에, 그것은 숨겨진 생성자의 매개 변수가 있습니다. 이는 잭슨이 실패하는 원인이된다.

  3. ==============================

    3.모든 필드가 JSON 데이터를 문자열이기 때문에, 모든 필드에 대한 문자열을 받아 MyClass의 생성자를 변경해보십시오. BTW, 거기에 JSON 타임 스탬프에 대한 표준 표현은 없다, 그래서 당신은 어쨌든 날짜 필드에 대한 변환을 수행해야합니다. 은 "가격"필드의 경우, 변경을 시도 할 수

    모든 필드가 JSON 데이터를 문자열이기 때문에, 모든 필드에 대한 문자열을 받아 MyClass의 생성자를 변경해보십시오. BTW, 거기에 JSON 타임 스탬프에 대한 표준 표현은 없다, 그래서 당신은 어쨌든 날짜 필드에 대한 변환을 수행해야합니다. 은 "가격"필드의 경우, 변경을 시도 할 수

    "price" : "10.00"
    

    "price" : 10.00
    

    JSON 데이터 단계; 즉,이 BigDecimal를로 읽을 수 있도록해야한다.

  4. ==============================

    4.당신은 하나의 자바 객체로 두 JSON 객체를 결합하려는 경우 여기 Genson 라이브러리 http://code.google.com/p/genson/있는 솔루션입니다. 다음 코드 단축 및 사용 Gensons 표준 컨버터하지만 그것은 예를 들어 덜 명확 것입니다 수 있습니다. 여기 장점은 매우 빠르고, 그래서 당신이 직접 스트리밍 API를 사용하고 있다는 점이다.

    당신은 하나의 자바 객체로 두 JSON 객체를 결합하려는 경우 여기 Genson 라이브러리 http://code.google.com/p/genson/있는 솔루션입니다. 다음 코드 단축 및 사용 Gensons 표준 컨버터하지만 그것은 예를 들어 덜 명확 것입니다 수 있습니다. 여기 장점은 매우 빠르고, 그래서 당신이 직접 스트리밍 API를 사용하고 있다는 점이다.

    class MyClassConverter implements Deserializer<MyClass> {
        @Override
        public MyClass deserialize(ObjectReader reader, Context ctx)
                throws TransformationException, IOException {
            reader.beginObject();
            MyClass myClass = new MyClass();
            for (; reader.hasNext();) {
                reader.next();
                if ("Person".equals(reader.name())) {
                    readPerson(reader, myClass);
                } else if ("Dog".equals(reader.name())) {
                    readDog(reader, myClass);
                }
            }
            reader.endObject();
            return myClass;
        }
    
        private void readPerson(ObjectReader reader, MyClass myClass) throws IOException {
            reader.beginObject();
            for (; reader.hasNext();) {
                reader.next();
                if ("id".equals(reader.name()))
                    myClass.setPersonsId(reader.valueAsString());
            }
            reader.endObject();
        }
    
        private void readDog(ObjectReader reader, MyClass myClass) throws IOException {
            reader.beginObject();
            for (; reader.hasNext();) {
                reader.next();
                if ("dateOfBirth".equals(reader.name()))
                    myClass.setDogsDateOfBirth(Timestamp.valueOf(reader.valueAsString()));
                else if ("price".equals(reader.name()))
                    myClass.setDogsPrice(new BigDecimal(reader.valueAsString()));
            }
            reader.endObject();
        }
    }
    

    당신은 당신이 분리 된 개체로 사람과 개를 가지고 다른 예를 원하는 경우에 당신은 Gensons 사용자 그룹에 요청할 수 있습니다.

    도움이 되었기를 바랍니다!

    편집하다 여기에 또 다른 버전 짧고 좋네요하지만 (나는 저자로 아마 오늘 새 버전을 출시 할 예정 :)) 릴리스 버전 0.91에 포함되지 않습니다 당신이 (당신은 또한 직렬화를 할 경우와 setter) @JsonProperty (the_name_from_json)와 게터에 주석을해야합니다 작동하게합니다. 당신이 필드 만 사용하려는 경우 Genson 어떤 게터 / 세터가 필요하지 않습니다 (그렇지 않으면 필드 avaible 경우 기본적으로는 게터 / 세터를 사용한다).

    Genson genson = new Genson.Builder().withDeserializerFactory(new MyClassConverterFactory()).create();
    MyClass myClass = genson.deserialize(json, MyClass.class);
    
    public static class MyClassConverterFactory implements Factory<Deserializer<MyClass>> {
        @SuppressWarnings("unchecked")
        @Override
        public Deserializer<MyClass> create(Type type, Genson genson) {
            BeanDescriptor<MyClass> myClassDescriptor = (BeanDescriptor<MyClass>) genson.getBeanDescriptorFactory().provide(MyClass.class, genson);
            return new MyClassConverter(myClassDescriptor);
        }
    }
    
    public static class MyClassConverter implements Deserializer<MyClass> {
        BeanDescriptor<MyClass> myClassDescriptor;
        public MyClassConverter(BeanDescriptor<MyClass> myClassDescriptor) {
            this.myClassDescriptor = myClassDescriptor;
        }
    
        @Override
        public MyClass deserialize(ObjectReader reader, Context ctx)
                throws TransformationException, IOException {
            reader.beginObject();
            MyClass myClass = new MyClass();
            for (; reader.hasNext();) {
                reader.next();
                if ("Person".equals(reader.name())) {
                    myClassDescriptor.deserialize(myClass, reader, ctx);
                } else if ("Dog".equals(reader.name())) {
                    myClassDescriptor.deserialize(myClass, reader, ctx);
                }
            }
            reader.endObject();
            return myClass;
        }
    }
    
  5. ==============================

    5.참고 : 나는 EclipseLink가 JAXB (목시) 리드와 JAXB (JSR-222) 전문가 그룹의 구성원입니다.

    참고 : 나는 EclipseLink가 JAXB (목시) 리드와 JAXB (JSR-222) 전문가 그룹의 구성원입니다.

    당신은 당신의 유스 케이스를 지원하기 위해 목시에 경로 기반의 매핑을 활용할 수 있습니다.

    내 수업

    @XmlPath 주석은 경로 기반 매핑을 지정하는 데 사용됩니다 :

    package forum12139380;
    
    import java.math.BigDecimal;
    import java.sql.Timestamp;
    import org.eclipse.persistence.oxm.annotations.XmlPath;
    import javax.xml.bind.annotation.*;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    public class MyClass {
    
        public MyClass() {
        }
    
        public MyClass(String personsId, Timestamp dogsDateOfBirth,
                BigDecimal dogsPrice) {
            this.personsId = personsId;
            this.dogsDateOfBirth = dogsDateOfBirth;
            this.dogsPrice = dogsPrice;
        }
    
        @XmlPath("Person/id/text()")
        private String personsId;
    
        @XmlPath("Dog/dateOfBirth/text()")
        private Timestamp dogsDateOfBirth;
    
        @XmlPath("Dog/price/text()")
        @XmlSchemaType(name="string")
        private BigDecimal dogsPrice;
    
        // ... Getters and Setters for each field
    
    }
    

    jaxb.properties

    다음 항목으로 도메인 모델과 동일한 패키지에 jaxb.properties라는 파일을 포함 할 필요가 당신의 JAXB 공급자로 MOXY를 지정하려면 :

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

    데모

    아래의 코드는 JSON의 뒤쪽으로 객체에 JSON 변환 한 것입니다.

    package forum12139380;
    
    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[] {MyClass.class}, properties);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            StreamSource json = new StreamSource("src/forum12139380/input.json");
            MyClass myClass = (MyClass) unmarshaller.unmarshal(json, MyClass.class).getValue();
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(myClass, System.out);
        }
    
    }
    

    input.xml / 출력

    아래는 데모 코드를 실행에서 입력 및 출력이다. 내 예제에서 나는 타임 스탬프의 목시의 기본 reprentation을 사용하고 있습니다. 당신은 (: JAXB 비 정렬 화 타임 스탬프를 참조) (때문에) XmlAdapter로 쉽게 표현을 제어 할 수 있습니다.

    {
       "Person" : {
          "id" : "2"
       },
       "Dog" : {
          "dateOfBirth" : "2012-08-20T00:00:00.0",
          "price" : "10.00"
       }
    }
    
  6. ==============================

    6.이 모든 답은 POJO를 사용하여 그것을 할 수있는 유일한 방법임을 의미한다. 물론, 웹 프로젝트, 봄 웹 서비스 프로젝트처럼, POJO의를하는 것이 중요하지만, 단지 단위 테스트를 위해 당신은 단지 일반적인 잭슨 JsonNode 개체를 사용할 수 있을까?

    이 모든 답은 POJO를 사용하여 그것을 할 수있는 유일한 방법임을 의미한다. 물론, 웹 프로젝트, 봄 웹 서비스 프로젝트처럼, POJO의를하는 것이 중요하지만, 단지 단위 테스트를 위해 당신은 단지 일반적인 잭슨 JsonNode 개체를 사용할 수 있을까?

    당신은 단순히 수없는 POJO 클래스를 사용하지 않고 잭슨 ObjectMapper를 사용하여 JsonNode으로 해제 직렬화? JsonNode의 인스턴스는 그 자체로는 법적 잭슨 POJO로 인정하지 않습니다? 난 당신이 JsonNode 인스턴스를 일단 당신이 JSON 개체를 얻을 수 없기 때문에 확신 같은 :

    node.get(0).get(1).get("nodename").asText();
    
  7. from https://stackoverflow.com/questions/12139380/how-to-convert-json-into-pojo-in-java-using-jackson by cc-by-sa and MIT license