Jackson 및 일반 유형 참조


107

다음과 같이 일반 메서드에 jackson json 라이브러리를 사용하고 싶습니다.

public MyRequest<T> tester() {
    TypeReference<MyWrapper<T>> typeRef = new TypeReference<MyWrapper<T>>();  
    MyWrapper<T> requestWrapper = (MyWrapper<T>) JsonConverter.fromJson(jsonRequest, typeRef);
    return requestWrapper.getRequest();
}

...

public class MyWrapper<T> {

    private MyRequest<T> request;

    public MyRequest<T> getRequest() {
        return request;
    }

    public void setRequest(MyRequest<T> request) {
        this.request = request;
    }
}


 public class MyRequest{
     private List<T> myobjects;

     public void setMyObjects(List<T> ets) {
         this.myobjects = ets;
     }

     @NotNull
     @JsonIgnore
     public T getMyObject() {
         return myobjects.get(0);
     }
}

이제 문제는 요청 객체 jackson 내부에있는 getMyObject ()를 호출 할 때 중첩 된 사용자 정의 객체를 LinkedHashMap으로 반환한다는 것입니다. T 객체를 반환해야한다고 지정하는 방법이 있습니까? 예 : Customer 유형의 개체를 보낸 경우 해당 목록에서 Customer가 반환되어야합니까?.

감사.


getT () 구현을 추가하십시오
Jim Garrison

이 질문은 stackoverflow.com/questions/6062011/… 과 유사 하지만 TypeFactory를 사용하여 유형을 지정하도록 제안했습니다. 그러나 컴파일 시간에 유형을 모릅니다 ...
techzen 2011-07-27

TypeFactory에는 정적 클래스가 필요하지 않은 메서드가 있습니다. createCollectionType 등.
StaxMan 2011

완전한 코드를 공유하십시오. 나는 또한 같은 문제에 직면하고 있습니다.
AZ_ 2013 년

하지인가 TypeReference추상적?
Kyle Delaney

답변:


194

이것은 Java 유형 삭제의 잘 알려진 문제입니다. T는 유형 변수 일 뿐이며 실제 클래스를 표시해야하며 일반적으로 Class 인수로 표시해야합니다. 이러한 정보가 없으면 할 수있는 최선의 방법은 경계를 사용하는 것입니다. 일반 T는 'T extends Object'와 거의 동일합니다. 그리고 Jackson은 JSON 객체를 맵으로 바인딩합니다.

이 경우 tester 메서드는 Class에 대한 액세스 권한이 있어야하며

JavaType type = mapper.getTypeFactory().
  constructCollectionType(List.class, Foo.class)

그리고

List<Foo> list = mapper.readValue(new File("input.json"), type);

16
작동합니다 : 다음을 수행했습니다. JavaType topMost = mapper.getTypeFactory (). constructParametricType (MyWrapper.class, ActualClassRuntime.class); 다음 readValue을했고, 마침내 :) 일
techzen

예, 작동합니다. Map / Collection 유형이 아닌 제네릭 유형을 생성하는 방법을 지적 해 주셔서 감사합니다!
StaxMan 2011

1
@StaxMan은 지금부터 이런 종류의 일에 ClassMate를 사용하는 것이 더 좋을까요?
husayt 2014 년

2
@husayt 예, 기술적으로 java-classmate lib가 우수합니다. 그러나 Jackson과의 통합은 Jackson의 자체 유형 추상화가 API의 일부이기 때문에 약간 까다 롭습니다. 장기적으로 Jackson이 포함되거나 dep를 통해 동급생 코드를 사용하도록하는 적절한 방법을 찾는 것이 좋습니다.
StaxMan 2014 년

1
나는 Jackson이 제네릭의 틈새처럼 느껴지는 것을 은폐 할 필요가 없다고 느낀다. 그러나 어느 쪽이든, 그것은 아주 잘한다.
Adrian Baker

6

'JavaType'이 작동합니다! 나는 json String의 List를 ArrayList Java Objects로 unmarshall (deserialize)하려고했으며 며칠 이후로 해결책을 찾기 위해 고군분투했습니다.
아래는 마침내 나에게 해결책을 준 코드입니다. 암호:

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 ;
    }  
}

TargetClass를 초기화하는 방법은 무엇입니까?
AZ_ 2013 년

작은 예를 보여주세요. Class <?> 대상을 전달하고 target.getClassName ()을 얻습니다.
AZ_

1
다음과 같이 생성자를 추가합니다. JsonMarshallerUnmarshaller <T> {private Class <T> targetClass; JsonMarshallerUnmarshaller (Class <T> c) {targetClass = c; }} 모든 곳에서 getClass를 수행하는 대신이 클래스를 사용하려면 'unmarshal'함수를 적절하게 변경하십시오.
rushidesai1

노트의 커플 : 코드는 모든 예외의 하위 유형이 있다는 지적에 의해 많이 단순화 할 수있다 IOException(필요 한 캐치) 및 기본 주석 인트로 스페 이미입니다 JacksonAnnotationIntrospector- 필요에 아무것도 할 수 없습니다 때문에 ObjectMapper, 단지 그것을 구성하고 그것을 작동합니다.
StaxMan 2015

그래서이 코드는 컴파일도하지 않습니다. 대신 붙여 넣을 실제 예제가 있습니까?
렌치

0

작업 예제를 포함 하도록 rushidesai1의 답변 을 수정 했습니다 .

JsonMarshaller.java

import java.io.*;
import java.util.*;

public class JsonMarshaller<T> {
    private static ClassLoader loader = JsonMarshaller.class.getClassLoader();

    public static void main(String[] args) {
        try {
            JsonMarshallerUnmarshaller<Station> marshaller = new JsonMarshallerUnmarshaller<>(Station.class);
            String jsonString = read(loader.getResourceAsStream("data.json"));
            List<Station> stations = marshaller.unmarshal(jsonString);
            stations.forEach(System.out::println);
            System.out.println(marshaller.marshal(stations));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("resource")
    public static String read(InputStream ios) {
        return new Scanner(ios).useDelimiter("\\A").next(); // Read the entire file
    }
}

산출

Station [id=123, title=my title, name=my name]
Station [id=456, title=my title 2, name=my name 2]
[{"id":123,"title":"my title","name":"my name"},{"id":456,"title":"my title 2","name":"my name 2"}]

JsonMarshallerUnmarshaller.java

import java.io.*;
import java.util.List;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;

public class JsonMarshallerUnmarshaller<T> {
    private ObjectMapper mapper;
    private Class<T> targetClass;

    public JsonMarshallerUnmarshaller(Class<T> targetClass) {
        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

        mapper = new ObjectMapper();
        mapper.getDeserializationConfig().with(introspector);
        mapper.getSerializationConfig().with(introspector);

        this.targetClass = targetClass;
    }

    public List<T> unmarshal(String jsonString) throws JsonParseException, JsonMappingException, IOException {
        return parseList(jsonString, mapper, targetClass);
    }

    public String marshal(List<T> list) throws JsonProcessingException {
        return mapper.writeValueAsString(list);
    }

    public static <E> List<E> parseList(String str, ObjectMapper mapper, Class<E> clazz)
            throws JsonParseException, JsonMappingException, IOException {
        return mapper.readValue(str, listType(mapper, clazz));
    }

    public static <E> List<E> parseList(InputStream is, ObjectMapper mapper, Class<E> clazz)
            throws JsonParseException, JsonMappingException, IOException {
        return mapper.readValue(is, listType(mapper, clazz));
    }

    public static <E> JavaType listType(ObjectMapper mapper, Class<E> clazz) {
        return mapper.getTypeFactory().constructCollectionType(List.class, clazz);
    }
}

Station.java

public class Station {
    private long id;
    private String title;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return String.format("Station [id=%s, title=%s, name=%s]", id, title, name);
    }
}

data.json

[{
  "id": 123,
  "title": "my title",
  "name": "my name"
}, {
  "id": 456,
  "title": "my title 2",
  "name": "my name 2"
}]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.