Jackson을 사용하여 JSON을 ArrayList <POJO>로 역 직렬화


97

MyPojoJSON에서 역 직렬화하는 데 관심 이있는 Java 클래스 가 있습니다. MyPojoDeMixIndeserialization을 지원하기 위해 특별한 MixIn 클래스를 구성했습니다 . MyPojo만 보유 int하고 String적절한 게터와 세터 결합 인스턴스 변수. MyPojoDeMixIn다음과 같이 보입니다.

public abstract class MyPojoDeMixIn {
  MyPojoDeMixIn(
      @JsonProperty("JsonName1") int prop1,
      @JsonProperty("JsonName2") int prop2,
      @JsonProperty("JsonName3") String prop3) {}
}

내 테스트 클라이언트에서 다음을 수행하지만 JsonMappingException유형 불일치와 관련 이 있기 때문에 컴파일 타임에는 작동하지 않습니다 .

ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }

나는 오직 하나만있는 "Response"객체를 생성함으로써이 문제를 완화 할 수 있다는 것을 알고 ArrayList<MyPojo>있지만, 반환하고자하는 모든 단일 유형에 대해 다소 쓸모없는 객체를 생성해야합니다.

나는 또한 JacksonInFiveMinutes를 온라인으로 보았지만 그 내용 Map<A,B>과 그것이 내 문제와 어떻게 관련되는지 이해하는 데 끔찍한 시간 을 보냈 습니다 . 당신이 말할 수 없다면, 나는 완전히 Java를 처음 접했고 Obj-C 배경에서 왔습니다. 그들은 구체적으로 다음과 같이 언급합니다.

POJO 및 "단순"유형에 대한 바인딩 외에도 일반 (유형화 된) 컨테이너에 대한 바인딩의 추가 변형이 하나 있습니다. 이 경우에는 소위 Type Erasure (Java에서 다소 역 호환 방식으로 제네릭을 구현하는 데 사용됨)로 인해 특수 처리가 필요하므로 Collection.class (컴파일되지 않음)와 같은 것을 사용할 수 없습니다.

따라서 데이터를 맵에 바인딩하려면 다음을 사용해야합니다.

Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });

어떻게 직접 역 직렬화 할 수 ArrayList있습니까?


답변:


149

TypeReference래퍼 를 사용하여 목록으로 직접 역 직렬화 할 수 있습니다 . 예제 방법 :

public static <T> T fromJSON(final TypeReference<T> type,
      final String jsonPacket) {
   T data = null;

   try {
      data = new ObjectMapper().readValue(jsonPacket, type);
   } catch (Exception e) {
      // Handle the problem
   }
   return data;
}

다음과 같이 사용됩니다.

final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);

TypeReference Javadoc


귀하의 답변은에 대한 내장 지원을 사용하는 방법에 대한 정보와 관련이있는 것 같습니다. 방법을 TypeReference모르겠습니다 ... 제네릭 사용 방법에 대한 지침은 위의 편집 내용을 참조하십시오.
tacos_tacos_tacos

음, 관련이 있습니다. 그러나 이것은 프로덕션에서 작동하는 코드의 일부입니다. 믹스 인은 잊어 버리고 내가 보여준 코드를 사용하십시오 (물론 POJO를 실제 빈 클래스의 이름으로 바꾸십시오).
Perception

귀하의 코드가 컴파일되었지만 arrayList.toString()약 을 인쇄하려고 할 때 런타임 예외가 발생 합니다 NullPointerException. 나는 이것이 POJO속성에 대한 올바른 명명 규칙을 따르지 않기 때문에 이것이 될 수 있다고 생각합니다. 즉 , 전체 문제는 웹 서비스가 반환 Prop1Member하고 내 개체가 Prop1. 이것이 내가 믹스 인을 사용하는 유일한 진짜 이유이므로 @JsonProperty순수한 객체에 대한 선언을 넣을 필요가 없습니다 .
tacos_tacos_tacos

1
배열을 시각적으로 검사하여 적어도 목록을 얻었는지 확인하십시오. 필요가 믹스 인 다시 추가 할 수 있다면 해야합니다 모든 것을 얻을 수있는 TypeReference과 함께 작업을 깔끔하게 직렬화.
Perception

2
@JsonProperty는 사람들이 그렇게 만드는 것처럼 사악하지 않습니다. 현장의 현재 표준화 상태 (최소)와 관련하여 공급 업체별 주석에서 벗어나기가 어렵습니다.
Perception

104

또 다른 방법은 배열을 유형으로 사용하는 것입니다. 예 :

ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);

이렇게하면 Type 개체의 모든 번거 로움을 피할 수 있으며, 목록이 정말로 필요한 경우 항상 다음과 같이 배열을 목록으로 변환 할 수 있습니다.

List<MyPojo> pojoList = Arrays.asList(pojos);

IMHO 이것은 훨씬 더 읽기 쉽습니다.

실제 목록 (수정 가능,의 제한 사항 참조 Arrays.asList())이되도록하려면 다음을 수행하십시오.

List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));

1
우아하지만 매개 변수로 전달하고 싶지 않은 MyPojo []. class 때문에 생성 할 수 없습니다.
Adrian Redgers

TypeFactory다음 답변에 설명 된대로 사용한다고 생각합니다 : stackoverflow.com/a/42458104/91497 은 유형을 지정하는 Jackson 방법입니다.
Jmini

32

이 변형은 더 간단하고 우아하게 보입니다.

CollectionType typeReference =
    TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);

3

나도 같은 문제가 있습니다. ArrayList로 변환 할 json이 있습니다.

계정은 다음과 같습니다.

Account{
  Person p ;
  Related r ;

}

Person{
    String Name ;
    Address a ;
}

위의 모든 클래스는 올바르게 주석 처리되었습니다. TypeReference> () {} 시도했지만 작동하지 않습니다.

그것은 나에게 Arraylist를 제공하지만 ArrayList에는 최종 값을 포함하는 더 많은 연결된 해시 맵을 포함하는 linkedHashMap이 있습니다.

내 코드는 다음과 같습니다.

public T unmarshal(String responseXML,String c)
{
    ObjectMapper mapper = new ObjectMapper();

    AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

    mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

    mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
    try
    {
      this.targetclass = (T) mapper.readValue(responseXML,  new TypeReference<ArrayList<T>>() {});
    }
    catch (JsonParseException e)
    {
      e.printStackTrace();
    }
    catch (JsonMappingException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    return this.targetclass;
}

마침내 문제를 해결했습니다. 다음과 같이 Json String의 List를 ArrayList로 직접 변환 할 수 있습니다.

JsonMarshallerUnmarshaller<T>{

     T targetClass ;

     public ArrayList<T> unmarshal(String jsonString)
     {
        ObjectMapper mapper = new ObjectMapper();

        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

        mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

        mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
        JavaType type = mapper.getTypeFactory().
                    constructCollectionType(ArrayList.class, targetclass.getClass()) ;
        try
        {
        Class c1 = this.targetclass.getClass() ;
        Class c2 = this.targetclass1.getClass() ;
            ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString,  type);
        return temp ;
        }
       catch (JsonParseException e)
       {
        e.printStackTrace();
       }
       catch (JsonMappingException e) {
           e.printStackTrace();
       } catch (IOException e) {
          e.printStackTrace();
       }

     return null ;
    }  

}

2

이것은 나를 위해 작동합니다.

@Test
public void cloneTest() {
    List<Part> parts = new ArrayList<Part>();
    Part part1 = new Part(1);
    parts.add(part1);
    Part part2 = new Part(2);
    parts.add(part2);
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(parts);

        List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
    } catch (Exception e) {
        //fail("failed.");
        e.printStackTrace();
    }

    //TODO: Assert: compare both list values.
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.