2012-10-26 3 views
1

다음과 같은 문제가 있습니다.java jackson parse generic 타입 객체를 포함하는 객체

json 요청을 제네릭 형식 필드가 들어있는 개체로 구문 분석해야합니다.

편집

나는 일반 클래스 형 (그래서 내가 일반적으로 교체하기 전에 그것이 작동되도록)를 사용하여 몇 가지 테스트를 만들었습니다. 이제 단일 요소에 대한 구문 분석이 효과적입니다.

문제점은 해당 클래스에서 목록 개체를 구문 분석해야 할 때입니다.

그래서 저는 Jackson에게 어떻게 든 T가 단지 AlbumModel 대신 유형 목록에 있다는 것을 알려야합니다.

다음은 내가 시도한 것입니다.

@Override 
    public ListResponseModel<AlbumModel> parse(String responseBody) throws Exception { 
    JavaType type = mapper.getTypeFactory().constructParametricType(ResponseModel.class, 
     AlbumModel.class); 
    return mapper.readValue(responseBody, 
     mapper.getTypeFactory().constructParametricType(ResponseModel.class, type)); 
    } 

위의 코드는 작동하지 않습니다. 이런 식의 해결책은 무엇입니까?

public class BaseResponseModel<T> { 

    @JsonProperty("data") 
    private T data; 

    @JsonProperty("paginations") 
    private PaginationModel pagination; 
} 

지금까지 나는 다음과 같은 코드를 가지고 있지만 항상 해시로 구문 분석 : List<T> data

이 같은 성공 : 같은 ListResponseModel에서

내 제네릭 형식 정의된다.

public class ResponseParser extends BaseJacksonMapperResponseParser<ResponseModel<AlbumModel>> { 

    public static final String TAG = ResponseParser.class.getSimpleName(); 

    @Override 
    public ResponseModel<AlbumModel> parse(String responseBody) throws Exception { 
     return mapper.readValue(responseBody, 
       mapper.getTypeFactory().constructParametricType(ResponseModel.class, AlbumModel.class)); 
    } 
} 

public abstract class BaseJacksonMapperResponseParser<T> implements HttpResponseParser<T> { 

    public static final String TAG = BaseJacksonMapperResponseParser.class.getSimpleName(); 

    public static ObjectMapper mapper = new ObjectMapper(); 

    static { 
     mapper.disable(Feature.FAIL_ON_UNKNOWN_PROPERTIES); 
     mapper.enable(Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); 
     mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true); 
    } 

} 

답변

5

나는 오이겐의 대답에 동의하지만, 단지 그것을 조금 확장하고 싶었다. 첫 번째 단계는 파싱 메서드를 리팩터링하여 두 번째 인수를 취하는 것입니다. 메서드에서 형식 참조를 할당하는 대신 호출자가 TypeReference 인스턴스를 전달해야합니다.

public BaseResponseModel<T> parse(String responseBody, TypeReference<T> ref) throws Exception { 
    return mapper.readValue(responseBody, ref); 
} 

불행하게도 구문 분석을 호출하는 코드를 표시하지 않습니다 당신의 조각은 - 그래서 내가 뭔가를 만들 수 있습니다 :

BaseResponseParser<Collection<Person>> parser = new BaseResponseParser<Collection<Person>>(); 
BaseResponseModel<Collection<Person>> result = parser.parse(jsonText, new TypeReference<Collection<Person>>(){}); 

주의 그 TypeReference 인스턴스가이 경우 컴파일, 그것은 유형 참조 우리가 기대하는 진정한 구체적인 수업에

런타임시 클래스에서 동일한 작업을 수행 할 수 있지만 TypeReference는 유형 T가 일반 콜렉션 일 때도 작동하기 때문에 조금 더 강력합니다. TypeReference 구현에는 일반적으로 지워지는 유형 정보를 보유 할 수있는 마법이 있습니다.

[업데이트]

Collection<Person>을 사용하도록 업데이트

. 참고 - 내가 아는 한까지 List<Whatever>도 작동해야하지만, 잭슨을 사용하여 컬렉션을 비 직렬화하는 프로젝트를 두 번 확인했습니다. 기본 클래스 컬렉션이 제대로 작동하도록했습니다.

+0

좋아요.이 작업을 시작합니다.이 작업을 단일 개체를 사용하여 만들었지 만 목록을 만들 수는 없습니다. 이것에 대한 정보를 조금 더 제공 할 수 있습니까? 지금까지 당신의 노력에 감사드립니다. – DArkO

+0

업데이트보기 - 더 일반적인 Collection 클래스를 사용해보세요. –

+0

나는 그것을 잘 만들었다. 이것과 유사하지만 당신은 한 가지 사실을 입증했습니다. 고마워. 내가 싫어하는 유일한 것은 .class를 보내고 generic 매개 변수를 정의해야하고 새로운 파서 (AlbumModel.class)과 같은 것으로 끝나야한다는 것입니다. – DArkO

0

잭슨을 사용하고 있으므로 응답 또는 요청을 제공하는지 여부에 따라 사용자 지정 JsonDeserializer 또는 JsonSerializer를 만들어야 할 수 있습니다. 내 답변에 표준보기를 원하기 때문에 날짜를 사용하여이 작업을 수행했습니다. 나는 100 % 긍정적이지는 않지만 일반 필드에서 작동 할 것입니다.

public class DateSerializer extends JsonSerializer<Date> { 

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZ"); 

    @Override 
    public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { 
     String dateString = dateFormat.format(value); 
     jgen.writeString(dateString); 
    } 

} 

그럼 난 그냥 그렇게처럼 내 클래스에 추가 : 여기에 내가 뭘하는지의 예입니다

당신의 타입 T는 런타임에 "삭제", 그래서 잭슨은 수행됩니다
@JsonSerialize(using = DateSerializer.class) 
public Date getModifiedDate() { 
    return modifiedDate; 
} 
2

T의 실제 유형이 무엇인지 알지 못하고이를 Map에 비 직렬화합니다. 파싱 ​​메서드의 두 번째 매개 변수는 Class<T> clazz 또는 TypeReference<T> 또는 java.lang.reflect.Type이 필요합니다.

편집 TypeReference의 마법에

작은 설명. 새로운 XX() {}을 작성할 때 익명 클래스를 작성하므로 typevariables (원하는 경우 매개 변수화 된 클래스) 인 경우 새로 X<List<Y>>() {},을 입력하면 런타임시 List<Y>을 Java 유형으로 검색 할 수 있습니다. 당신이했던 것처럼 매우 유사합니다

abstract class MyGenericClass<T> {} 
class MySpecializedClass extends MyGenericClass<List<Y>> {} 
+0

작동합니다. 고맙습니다. –

관련 문제