2013-05-08 16 views
13

私はJSONオブジェクトにのようなものがあります。ジャクソンの列挙型フィールドを無視する方法JSONからオブジェクトへのマッピング?

:私は上記のJSONをマップしようとしていますなど

{"name":"John", "grade":"A"} 

または

{"name":"Mike", "grade":"B"} 

または

{"name":"Simon", "grade":"C"} 

@JsonIgnoreProperties(ignoreUnknown = true) 
public class Employee{ 
     @JsonIgnoreProperties(ignoreUnknown = true) 
     public enum Grade{ A, B, C } 
     Grade grade; 
     String name; 

    public Grade getGrade() { 
    return grade; 
    } 

    public void setGrade(Grade grade) { 
    this.grade = grade; 
    } 

    public String getName() { 
    return name; 
    } 

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

上記のマッピングが正常に動作しますが、将来的にはより多くの「グレード」タイプは、既存のマッピングを破壊し、次の例外

05-08 09:56:28.130: W/System.err(21309): org.codehaus.jackson.map.JsonMappingException: Can not construct instance of Employee from String value 'D': value not one of declared Enum instance names 

をスローD、Eなどがへの道はありましょうがあるだろう列挙型で未知のフィールドを無視しますか?私はあなたがGrade列挙のための外部deserializerを定義するべきだと思い

おかげ

+2

注釈 '@ JsonIgnoreProperties'は、' Enum'型の期待通りの動作をしません。未知のPOJOプロパティを無視することしかできません(現在)。しかし、私はこれが改善アイデアとして理にかなっていると思います。だから、[Jackson databind](https://github.com/FasterXML/jackson-databind)プロジェクトで問題を提出できますか?もしそうなら、それはおそらくジャクソン2.3で追加することができますか? – StaxMan

+3

答えは少し冗長です。最も簡単で簡単な解決策を探している人には、 'READ_UNKNOWN_ENUM_VALUES_AS_NULL' [脱直列化機能](https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features#value-conversions)をtrueに設定してください。 – Jonik

答えて

19

私は列挙するために追加のフィールドを追加 - UNKNOWN:今すぐ

enum Grade { 
    A, B, C, UNKNOWN; 

    public static Grade fromString(String value) { 
     for (Grade grade : values()) { 
      if (grade.name().equalsIgnoreCase(value)) { 
       return grade; 
      } 
     } 

     return UNKNOWN; 
    } 
} 
class Employee { 

    @JsonDeserialize(using = GradeDeserializer.class) 
    private Grade grade; 
    private String name; 

    public Grade getGrade() { 
     return grade; 
    } 

    public void setGrade(Grade grade) { 
     this.grade = grade; 
    } 

    public String getName() { 
     return name; 
    } 

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

    @Override 
    public String toString() { 
     return "Employee [grade=" + grade + ", name=" + name + "]"; 
    } 
} 

、パーサはそのようになります。

class GradeDeserializer extends JsonDeserializer<Grade> { 
    @Override 
    public Grade deserialize(JsonParser parser, DeserializationContext context) 
      throws IOException, JsonProcessingException { 
     return Grade.fromString(parser.getValueAsString()); 
    } 
} 

を使用例:

public class JacksonProgram { 

    public static void main(String[] args) throws Exception { 
     ObjectMapper objectMapper = new ObjectMapper(); 
     JsonFactory jsonFactory = new JsonFactory(); 
     JsonParser parser = jsonFactory 
       .createJsonParser("{\"name\":\"John\", \"grade\":\"D\"}"); 
     Employee employee = objectMapper.readValue(parser, Employee.class); 
     System.out.println(employee); 
    } 

} 

出力:

Employee [grade=UNKNOWN, name=John] 

フィールドを追加しない場合は、たとえばnullを返します。

+0

ありがとう、それは働いた。 – Saqib

+1

列挙型のUNKNOWNインスタンスを持つことは、私にとっては貧しい選択です。ステファンのソリューションをREAD_UNKNOWN_ENUM_VALUES_AS_NULL機能で使用すると、nullが生成されます。 – Tom

+3

UNKNOWNは、この時点で値が不明であることを示します。 nullは値が設定されていないことを意味します。状況によっては混乱し、NPEを引き起こす可能性があります。また、enum値にメソッドが含まれている場合、よりエレガントな方法で特別なnull処理を実装できます。私にとっては、READ_UNKNOWN_ENUM_VALUES_AS_NULL機能を備えたソリューションも適しています。たぶん、私よりも優れています... –

19

私はこのような操作を行うための方法を発見した、次のとおりです。

public static void main(String[] args) throws JsonParseException, JsonMappingException, UnsupportedEncodingException, IOException { 
    String json = "{\"name\":\"John\", \"grade\":\"D\"}"; 

    ObjectMapper mapper = new ObjectMapper(); 
    mapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true); 
    Employee employee = mapper.readValue(new ByteArrayInputStream(json.getBytes("UTF-8")), Employee.class); 

    System.out.println(employee.getGrade()); 
} 

この出力:

ヌル

他のクラス:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 

@JsonIgnoreProperties(ignoreUnknown = true) 
public class Employee { 
    private String name; 
    private Grade grade; 

    public String getName() { 
     return name; 
    } 

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

    public Grade getGrade() { 
     return grade; 
    } 

    public void setGrade(Grade grade) { 
     this.grade = grade; 
    } 
} 



import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 

@JsonIgnoreProperties(ignoreUnknown = true) 
public enum Grade {A, B, C} 

Iの避難所't com eを使用して、注釈でこれを実行します。

こちらがお役に立てば幸いです。

+0

ありがとう、それは働いた – Saqib

+0

@stefaan:この答えは私のために働いた!私が見逃していたのは、 DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULLでした。 – Arthulia

+0

ジャクソン2.8以降、READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUEもあります。これにより、nullではなくデフォルト値を設定できます。 https://fasterxml.github.io/jackson-databind/javadoc/2.8/com/fasterxml/jackson/databind/DeserializationFeature.html#READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE – Rick

1

@JsonCreatorは、@JsonDeserializeと比較して、より簡潔な解を提供します。

valueOf()(この例ではsafeValueOf()と呼ばれます)の注釈を@JsonCreatorにしてから、実装を使用して文字列をデシリアライズします。

実装は列挙型の内部にあることに注意してください。変更なしで他のオブジェクトのフィールドとして使用できます。

以下の解決策はユニットテストでラップされているため、直接実行することができます。

import static junit.framework.TestCase.assertEquals; 

import java.io.IOException; 

import org.junit.Test; 

import com.fasterxml.jackson.annotation.JsonCreator; 
import com.fasterxml.jackson.databind.ObjectMapper; 

public class EmployeeGradeTest { 

    public enum Grade { 
     A, B, C, OTHER; 

     @JsonCreator 
     public static Grade safeValueOf(String string) { 
      try { 
       return Grade.valueOf(string); 
      } catch (IllegalArgumentException e) { 
       return OTHER; 
      } 
     } 
    } 

    @Test 
    public void deserialize() throws IOException { 
     assertEquals(Grade.A, new ObjectMapper().readValue("\"A\"", Grade.class)); 
    } 

    @Test 
    public void deserializeNewValue() throws IOException { 
     assertEquals(Grade.OTHER, new ObjectMapper().readValue("\"D\"", Grade.class)); 
    } 
} 
関連する問題