json 문자열이 있는데 다음 클래스로 직렬화 해제해야합니다.
class Data <T> {
int found;
Class<T> hits
}
어떻게합니까? 이것은 일반적인 방법입니다
mapper.readValue(jsonString, Data.class);
그러나 T가 의미하는 것을 어떻게 언급합니까?
json 문자열이 있는데 다음 클래스로 직렬화 해제해야합니다.
class Data <T> {
int found;
Class<T> hits
}
어떻게합니까? 이것은 일반적인 방법입니다
mapper.readValue(jsonString, Data.class);
그러나 T가 의미하는 것을 어떻게 언급합니까?
답변:
사용하는 TypeReference
각 제네릭 형식에 대한 개체 를 생성하고 역 직렬화에 사용해야합니다. 예를 들어-
mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
Data<T>
. 유형이 아닙니다. 실제 클래스를 지정해야합니다. 그렇지 않으면와 동일합니다 Data<Object>
.
TypeReference
무엇입니까? 그렇 com.fasterxml.jackson.core.type
습니까?
그렇게 할 수 없습니다 :과 같이 완전히 해결 된 유형을 지정해야합니다 Data<MyType>
. T
변수 일 뿐이며 의미가 없습니다.
그러나 그것이 T
정적으로 알려진 것이 아니라는 것을 의미한다면 , TypeReference
동적으로 동등한 것을 만들어야합니다 . 언급 된 다른 질문은 이미 이것을 언급 할 수 있지만 다음과 같이 보일 것입니다.
public Data<T> read(InputStream json, Class<T> contentClass) {
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass);
return mapper.readValue(json, type);
}
TypeReference
. return mapper.readValue(json, clazz);
정확히 무엇이 문제입니까?
TypeFactory
.. 를 사용해야합니다 . 답변을 편집하겠습니다.
먼저 직렬화를 수행 한 다음 직렬화 해제를 수행 할 수 있습니다.
따라서 직렬화를 수행 할 때 @JsonTypeInfo
Jackson이 클래스 정보를 json 데이터에 쓰도록 해야합니다 . 당신이 할 수있는 일은 다음과 같습니다
Class Data <T> {
int found;
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
Class<T> hits
}
그런 다음 deserialize하면 Jackson이 변수 적중이 실제로 런타임에 클래스로 데이터를 deserialize 한 것을 알 수 있습니다.
Util 클래스에서 정적 메소드를 작성하십시오. 파일에서 Json을 읽고 있습니다. 당신은 또한 readValue에 문자열을 줄 수 있습니다
public static <T> T convertJsonToPOJO(String filePath, Class<?> target) throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(new File(filePath), objectMapper .getTypeFactory().constructCollectionType(List.class, Class.forName(target.getName())));
}
용법:
List<TaskBean> list = Util.<List<TaskBean>>convertJsonToPOJO("E:/J2eeWorkspaces/az_workspace_svn/az-client-service/dir1/dir2/filename.json", TaskBean.class);
역 직렬화해야하는 JSON 문자열에는 parameter에 대한 유형 정보가 포함되어야합니다 T
.
Jackson이 매개 변수 유형에 대한 유형 정보 를 JSON 문자열에서 읽거나 쓸 수 있도록 매개 변수 T
로 클래스에 전달할 수있는 모든 클래스에 Jackson 주석을 넣어야 합니다.Data
T
T
추상 클래스를 확장하는 모든 클래스가 될 수 있다고 가정 해 봅시다 Result
.
class Data <T extends Result> {
int found;
Class<T> hits
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
@JsonSubTypes.Type(value = ImageResult.class, name = "ImageResult"),
@JsonSubTypes.Type(value = NewsResult.class, name = "NewsResult")})
public abstract class Result {
}
public class ImageResult extends Result {
}
public class NewsResult extends Result {
}
매개 변수로 전달 될 수있는 각 클래스 (또는 공통 수퍼 타입) T
에 주석을 달면 Jackson은 매개 변수 T
에 대한 정보를 JSON에 포함합니다. 그런 다음 T
컴파일 타임에 매개 변수 를 몰라도 이러한 JSON을 직렬화 해제 할 수 있습니다 .
이 Jackson 문서 링크 는 다형성 역 직렬화에 대해 설명하지만이 질문을 참조하는 데 유용합니다.
Jackson 2.5부터는이를 해결하는 우아한 방법 은 매개 변수화 된 클래스와 해당 매개 변수화 된 형식을 지정하여 Jackson을 확실하게 정의 할 수 있는
TypeFactory.constructParametricType (Class parametrized, Class ... parameterClasses) 메서드를 사용하는 것 JavaType
입니다.
역 직렬화하려는 Data<String>
경우 다음을 수행 할 수 있습니다.
// the json variable may be a String, an InputStream and so for...
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class);
Data<String> data = mapper.readValue(json, type);
클래스가 여러 매개 변수화 된 유형을 선언 한 경우 실제로 어렵지 않습니다.
class Data <T, U> {
int found;
Class<T> hits;
List<U> list;
}
우리는 할 수 있습니다 :
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class, Integer);
Data<String, Integer> data = mapper.readValue(json, type);
public class Data<T> extends JsonDeserializer implements ContextualDeserializer {
private Class<T> cls;
public JsonDeserializer createContextual(DeserializationContext ctx, BeanProperty prop) throws JsonMappingException {
cls = (Class<T>) ctx.getContextualType().getRawClass();
return this;
}
...
}
스칼라를 사용하고 컴파일 타임에 제네릭 형식을 알고 있지만 모든 응용 프로그램의 모든 곳에서 TypeReference를 수동으로 전달하고 싶지 않은 경우 다음 코드를 사용할 수 있습니다 (jackson 2.9.5).
def read[T](entityStream: InputStream)(implicit typeTag: WeakTypeTag[T]): T = {
//nathang: all of this *crazy* scala reflection allows us to handle List[Seq[Map[Int,Value]]]] without passing
// new TypeReference[List[Seq[Map[Int,Value]]]]](){} to the function
def recursiveFindGenericClasses(t: Type): JavaType = {
val current = typeTag.mirror.runtimeClass(t)
if (t.typeArgs.isEmpty) {
val noSubtypes = Seq.empty[Class[_]]
factory.constructParametricType(current, noSubtypes:_*)
}
else {
val genericSubtypes: Seq[JavaType] = t.typeArgs.map(recursiveFindGenericClasses)
factory.constructParametricType(current, genericSubtypes:_*)
}
}
val javaType = recursiveFindGenericClasses(typeTag.tpe)
json.readValue[T](entityStream, javaType)
}
다음과 같이 사용할 수 있습니다.
read[List[Map[Int, SomethingToSerialize]]](inputStream)
Jackson을 사용하여 일반 JSON 문자열을 Java 객체로 직렬화 해제하려면 다음이 필요합니다.
JSON 클래스를 정의합니다.
속성 매핑을 수행하십시오.
최종 코드, 테스트 및 사용 준비 완료 :
static class MyJSON {
private Map<String, Object> content = new HashMap<>();
@JsonAnySetter
public void setContent(String key, Object value) {
content.put(key, value);
}
}
String json = "{\"City\":\"Prague\"}";
try {
MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class);
String jsonAttVal = myPOJO.content.get("City").toString();
System.out.println(jsonAttVal);
} catch (IOException e) {
e.printStackTrace();
}
중요 :
@JsonAnySetter
주석은 필수이며 일반적인 JSON 구문 분석 및 채우기를 보장합니다.
중첩 배열이있는 복잡한 경우 Baeldung 참조를 참조하십시오 : https://www.baeldung.com/jackson-mapping-dynamic-object