Jackson 열거 형 직렬화 및 DeSerializer
JAVA 1.6과 Jackson 1.9.9를 사용하고 있습니다.
public enum Event {
FORGOT_PASSWORD("forgot password");
private final String value;
private Event(final String description) {
this.value = description;
}
@JsonValue
final String value() {
return this.value;
}
}
@JsonValue를 추가했는데 객체를 직렬화하는 작업을 수행하는 것 같습니다.
{"event":"forgot password"}
하지만 역 직렬화하려고하면
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.globalrelay.gas.appsjson.authportal.Event from String value 'forgot password': value not one of declared Enum instance names
내가 여기서 무엇을 놓치고 있습니까?
@xbakesx 가 지적한 serializer / deserializer 솔루션은 열거 형 클래스를 JSON 표현에서 완전히 분리하려는 경우 훌륭한 솔루션 입니다.
당신이 기반으로 독립적 인 솔루션 구현을 선호하는 경우 또는, @JsonCreator
및 @JsonValue
주석이 더 편리 할 것입니다.
@Stanley 의 예제를 활용 하여 다음은 완전한 자체 포함 솔루션 (Java 6, Jackson 1.9)입니다.
public enum DeviceScheduleFormat {
Weekday,
EvenOdd,
Interval;
private static Map<String, DeviceScheduleFormat> namesMap = new HashMap<String, DeviceScheduleFormat>(3);
static {
namesMap.put("weekday", Weekday);
namesMap.put("even-odd", EvenOdd);
namesMap.put("interval", Interval);
}
@JsonCreator
public static DeviceScheduleFormat forValue(String value) {
return namesMap.get(StringUtils.lowerCase(value));
}
@JsonValue
public String toValue() {
for (Entry<String, DeviceScheduleFormat> entry : namesMap.entrySet()) {
if (entry.getValue() == this)
return entry.getKey();
}
return null; // or fail
}
}
2015 년 6 월 (Jackson 2.6.2 이상)의 커밋 을 통해 다음 과 같이 간단히 작성할 수 있습니다.
public enum Event {
@JsonProperty("forgot password")
FORGOT_PASSWORD;
}
단일 인수를 사용하여 주석을 추가하는 정적 팩토리 메소드를 작성해야합니다 @JsonCreator
(Jackson 1.2부터 사용 가능).
@JsonCreator
public static Event forValue(String value) { ... }
JsonCreator 주석에 대한 자세한 내용은 여기를 참조하십시오 .
실제 답변 :
열거 형의 기본 deserializer는 deserialize에 사용하므로을 사용 .name()
하지 않습니다 @JsonValue
. @OldCurmudgeon이 지적했듯이 값 {"event": "FORGOT_PASSWORD"}
과 일치 하도록 전달해야 .name()
합니다.
다른 옵션 (쓰기 및 읽기 json 값이 동일하다고 가정) ...
더 많은 정보:
Jackson으로 직렬화 및 역 직렬화 프로세스를 관리하는 또 다른 방법이 있습니다. 고유 한 사용자 정의 시리얼 라이저 및 디시리얼라이저를 사용하도록 이러한 주석을 지정할 수 있습니다.
@JsonSerialize(using = MySerializer.class)
@JsonDeserialize(using = MyDeserializer.class)
public final class MyClass {
...
}
그런 다음 다음 MySerializer
과 MyDeserializer
같이 작성해야합니다 .
MySerializer
public final class MySerializer extends JsonSerializer<MyClass>
{
@Override
public void serialize(final MyClass yourClassHere, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
{
// here you'd write data to the stream with gen.write...() methods
}
}
MyDeserializer
public final class MyDeserializer extends org.codehaus.jackson.map.JsonDeserializer<MyClass>
{
@Override
public MyClass deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
{
// then you'd do something like parser.getInt() or whatever to pull data off the parser
return null;
}
}
마지막 JsonEnum
으로, 메소드 getYourValue()
를 사용하여 직렬화 하는 열거 형 으로이 작업을 수행 하는 경우 직렬 변환기와 직렬화 해제 프로그램은 다음과 같습니다.
public void serialize(final JsonEnum enumValue, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
{
gen.writeString(enumValue.getYourValue());
}
public JsonEnum deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
{
final String jsonValue = parser.getText();
for (final JsonEnum enumValue : JsonEnum.values())
{
if (enumValue.getYourValue().equals(jsonValue))
{
return enumValue;
}
}
return null;
}
매우 훌륭하고 간결한 솔루션을 찾았습니다. 특히 enum 클래스를 수정할 수없는 경우에 유용합니다. 그런 다음 특정 기능이 활성화 된 사용자 정의 ObjectMapper를 제공해야합니다. 이러한 기능은 Jackson 1.6부터 사용할 수 있습니다. 따라서 toString()
열거 형에 메소드 만 작성하면됩니다 .
public class CustomObjectMapper extends ObjectMapper {
@PostConstruct
public void customConfiguration() {
// Uses Enum.toString() for serialization of an Enum
this.enable(WRITE_ENUMS_USING_TO_STRING);
// Uses Enum.toString() for deserialization of an Enum
this.enable(READ_ENUMS_USING_TO_STRING);
}
}
사용 가능한 열거 관련 기능이 더 있습니다. 여기를 참조하십시오.
https://github.com/FasterXML/jackson-databind/wiki/Serialization-Features https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features
모든 속성의 역 직렬화를 사용자 정의 할 수 있습니다.
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
처리 할 속성에 annotationJsonDeserialize ( )를 사용하여 역 직렬화 클래스를 선언하십시오 . 이것이 열거 형인 경우 :
@JsonDeserialize(using = MyEnumDeserialize.class)
private MyEnum myEnum;
이런 식으로 클래스는 속성을 역 직렬화하는 데 사용됩니다. 이것은 전체 예입니다.
public class MyEnumDeserialize extends JsonDeserializer<MyEnum> {
@Override
public MyEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
MyEnum type = null;
try{
if(node.get("attr") != null){
type = MyEnum.get(Long.parseLong(node.get("attr").asText()));
if (type != null) {
return type;
}
}
}catch(Exception e){
type = null;
}
return type;
}
}
이 시도.
공개 열거 형 이벤트 { FORGOT_PASSWORD ( "암호 분실"); 개인 최종 문자열 값; 비공개 이벤트 (최종 문자열 설명) { this.value = 설명; } 비공개 이벤트 () { this.value = this.name (); } J 최종 문자열 값 () { 이것을 돌려줍니다 .value; } }
다음은 맵 대신 문자열 값을 사용하는 다른 예입니다.
public enum Operator {
EQUAL(new String[]{"=","==","==="}),
NOT_EQUAL(new String[]{"!=","<>"}),
LESS_THAN(new String[]{"<"}),
LESS_THAN_EQUAL(new String[]{"<="}),
GREATER_THAN(new String[]{">"}),
GREATER_THAN_EQUAL(new String[]{">="}),
EXISTS(new String[]{"not null", "exists"}),
NOT_EXISTS(new String[]{"is null", "not exists"}),
MATCH(new String[]{"match"});
private String[] value;
Operator(String[] value) {
this.value = value;
}
@JsonValue
public String toStringOperator(){
return value[0];
}
@JsonCreator
public static Operator fromStringOperator(String stringOperator) {
if(stringOperator != null) {
for(Operator operator : Operator.values()) {
for(String operatorString : operator.value) {
if (stringOperator.equalsIgnoreCase(operatorString)) {
return operator;
}
}
}
}
return null;
}
}
JSON 객체를 열거 형으로 역 직렬화하기 위해 수행 할 수있는 다양한 방법이 있습니다. 내가 가장 좋아하는 스타일은 내부 클래스를 만드는 것입니다.
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.fasterxml.jackson.annotation.JsonFormat.Shape.OBJECT;
@JsonFormat(shape = OBJECT)
public enum FinancialAccountSubAccountType {
MAIN("Main"),
MAIN_DISCOUNT("Main Discount");
private final static Map<String, FinancialAccountSubAccountType> ENUM_NAME_MAP;
static {
ENUM_NAME_MAP = Arrays.stream(FinancialAccountSubAccountType.values())
.collect(Collectors.toMap(
Enum::name,
Function.identity()));
}
private final String displayName;
FinancialAccountSubAccountType(String displayName) {
this.displayName = displayName;
}
@JsonCreator
public static FinancialAccountSubAccountType fromJson(Request request) {
return ENUM_NAME_MAP.get(request.getCode());
}
@JsonProperty("name")
public String getDisplayName() {
return displayName;
}
private static class Request {
@NotEmpty(message = "Financial account sub-account type code is required")
private final String code;
private final String displayName;
@JsonCreator
private Request(@JsonProperty("code") String code,
@JsonProperty("name") String displayName) {
this.code = code;
this.displayName = displayName;
}
public String getCode() {
return code;
}
@JsonProperty("name")
public String getDisplayName() {
return displayName;
}
}
}
In the context of an enum, using @JsonValue
now (since 2.0) works for serialization and deserialization.
According to the jackson-annotations javadoc for @JsonValue
:
NOTE: when use for Java enums, one additional feature is that value returned by annotated method is also considered to be the value to deserialize from, not just JSON String to serialize as. This is possible since set of Enum values is constant and it is possible to define mapping, but can not be done in general for POJO types; as such, this is not used for POJO deserialization.
So having the Event
enum annotated just as above works (for both serialization and deserialization) with jackson 2.0+.
Besides using @JsonSerialize @JsonDeserialize, you can also use SerializationFeature and DeserializationFeature (jackson binding) in the object mapper.
Such as DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, which give default enum type if the one provided is not defined in the enum class.
The simplest way I found is using @JsonFormat.Shape.OBJECT annotation for the enum.
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum MyEnum{
....
}
참고URL : https://stackoverflow.com/questions/12468764/jackson-enum-serializing-and-deserializer
'Programming' 카테고리의 다른 글
Linux에서 출력 라인 당 하나의 파일 이름을 어떻게 나열합니까? (0) | 2020.05.07 |
---|---|
Android Check 인터넷 연결 (0) | 2020.05.07 |
node_modules를 삭제하는 방법-Windows에서 깊은 중첩 폴더 (0) | 2020.05.07 |
ExecutorService의 이름 지정 스레드 및 스레드 풀 (0) | 2020.05.07 |
ADB 쉘 입력 이벤트 (0) | 2020.05.07 |