私は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 で指摘されているシリアライザ/デシリアライザソリューションは、完全に分離する場合に最適なソリューションです。そのJSON表現からのあなたのenumクラス。
あるいは、自己完結型のソリューションを好む場合は、@JsonCreator
および@JsonValue
アノテーションに基づく実装がより便利です。
したがって、 @ Stanley の例を活用すると、次のような完全な自己完結型ソリューションになります(Java 6)。 、ジャクソン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アノテーション の詳細についてはこちら をご覧ください。
実際の答え:
Enumのデフォルトのデシリアライザは.name()
を使ってデシリアライズするので、@JsonValue
を使いません。 @OldCurmudgeonが指摘したように、.name()
の値と一致させるには{"event": "FORGOT_PASSWORD"}
を渡す必要があります。
他のオプション(writeとreadの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;
}
}
ちょっと最後に、特にこれをメソッドgetYourValue()
でシリアライズする列挙JsonEnum
にするために、あなたのシリアライザとデシリアライザはこのように見えるかもしれません:
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以降で利用可能です。それであなたはあなたのenumに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);
}
}
利用可能なenum関連の機能が他にもあります。こちらを参照してください。
https://github.com/FasterXML/jackson-databind/wiki/Serialization-Featureshttps:// github.com/FasterXML/jackson-databind/wiki/Deserialization-Features
任意の属性に対して逆シリアル化をカスタマイズできます。
処理される属性にannotationJsonDeserialize(import com.fasterxml.jackson.databind.annotation.JsonDeserialize
)を使用して逆シリアル化クラスを宣言します。これがEnumの場合:
@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;
}
}
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;
}
}
}
これは、マップの代わりに文字列値を使用する別の例です。
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;
}
}
これを試して。
public enumイベント{ FORGOT_PASSWORD( "パスワードを忘れた"); プライベート最終文字列値private Event(最後の文字列の説明){ this.value = description; } private Event(){[.____ this.value = this.name(); @JsonValue final String value(){ return this.value ; } }
列挙型のコンテキストでは、@JsonValue
now(2.0以降)を使用すると、直列化およびの直列化復元に使用できます。
@JsonValue
の jackson-annotationsのjavadocによると、 :
注:Java列挙型を使用する場合、1つの追加機能として、シリアライズするJSON Stringだけでなく、注釈付きメソッドによって返される値もデシリアライズする値と見なされることがあります。 Enum値のセットは定数であり、マッピングを定義することは可能であるため、これは可能ですが、POJO型では一般的にはできません。そのため、これはPOJOの逆シリアル化には使用されません。
したがって、Event
列挙型に上記のようにアノテーションを付けることは、(serializationとdeserializationの両方のために)jackson 2.0+でうまくいきます。
@JsonSerialize @JsonDeserializeを使用する以外に、オブジェクトマッパーでSerializationFeatureおよびDeserializationFeature(jacksonバインディング)を使用することもできます。
DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUEなど。指定されたものがenumクラスで定義されていない場合はデフォルトのenum型を指定します。
私が見つけた最も簡単な方法は、enumに@ JsonFormat.Shape.OBJECTアノテーションを使うことです。
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum MyEnum{
....
}