LoginSignup
48
41

More than 5 years have passed since last update.

Jackson ObjectMapper Tips

Posted at

メンバ名がハイフン(-)区切りの JSON を Java Bean にデシリアライズする方法

メンバ名がハイフン(-)区切りの JSON を Jackson の ObjectMapper でデシリアラズしようとすると例外 UnrecognizedPropertyException: Unrecognized field "xxx-xxx" (Class jp.co.ilu.abx2.result.json.Order), not marked as ignorable が発生する。
この場合、@JsonProperty アノテーションを使用して、メンバ名を指定してやればよい。

注文を表す Order Bean に、@JsonProperty アノテーションを使用してみる。

Order.java
public class Order {
  private int orderId;

  @JsonProperty("order-id")
  public int getOrderId() {
    return this.orderId;
  }

  @JsonProperty("order-id")
  public void setOrderId(int orderId) {
    this.orderId = orderId;
  }
}

JSON をデシリアライズする例は:

例-1
ObjectMapper mapper = new ObjectMapper();
Order order = mapper.readValue("{ \"order-id\":480310 }", Order.class);
System.out.println(order.getOrderId());

Java Bean がインターフェースと実装に分離している場合

実装クラスを @JsonTypeInfo アノテーションを使用して指定してやるとデシリアライズできるようになる。

先ほどの Order Bean を Order インターフェースとその実装である OrderImpl とに分離し、Order の一覧をもつ Person インターフェースとその実装である PersonImpl を、@JsonTypeInfo アノテーションを使って次のように実装することができる。

Order.java
public interface Order {
  int getOrderId();
}
OrderImpl.java
class OrderImpl implements Order{
  private int orderId;

  @JsonProperty("order-id")
  public int getOrderId() {
    return this.orderId;
  }

  @JsonProperty("order-id")
  public void setOrderId(int orderId) {
    this.orderId = orderId;
  }
}
Person.java
public interface Person {
  String getName();

  Collection<Order> getOrders();
}
PersonImpl
class PersonImpl implements Person {
  private String name;
  private Collection<Order> orders;

  public String getName() {
    return this.name;
  }

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

  @JsonTypeInfo(use=JsonTypeInfo.Id.NONE, defaultImpl=OrderImpl.class)
  public Collection<Order> getOrders() {
    return this.orders;
  }

  @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, defaultImpl=OrderImpl.class)
  public void setOrders(Collection<Order> orders) {
    this.orders = orders;
  }
}

Order と Person を実際にデシリアライズする例は:

例-2
String jsonText = "{\"name\":\"sunny4381\",\"orders\":[{ \"order-id\":480310 },{ \"order-id\":480320 }]}";
ObjectMapper mapper = new ObjectMapper();
Person person = mapper.readValue(jsonText, PersonImpl.class);
System.out.println(person.getName());

PersonImpl.getOrders() メソッドの @JsonTypeInfo アノテーションには、use=JsonTypeInfo.Id.NONE を指定している。
これを指定しないと、PersonImpl クラスのインスタンスを ObjectMapper を使用して JSON にシリアライズする際に、余計なメンバ@type が出力される。
use=JsonTypeInfo.Id.NONE を指定することで、シリアライズした際に、余計なメンバーが出力されることを抑制している。

JSON に余分なメンバが存在していてもシリアライズに成功するようにする方法

Jackson ObjectMapper の既定の動作では、JSON に余分なメンバが存在している場合、例外 UnrecognizedPropertyException: Unrecognized field "extra-member" (Class jp.co.ilu.abx2.result.json.Order), not marked as ignorable が発生する。
これを抑制するには、@JsonIgnoreProperties(ignoreUnknown=true) アノテーションをクラスに指定してやる。

先ほどの OrderImpl クラスと PersonImpl クラスに @JsonIgnoreProperties(ignoreUnknown=true) アノテーションを指定してやると、次のようになる。

OrderImpl.java
@JsonIgnoreProperties(ignoreUnknown=true)
class OrderImpl implements Order{
  private int orderId;

  @JsonProperty("order-id")
  public int getOrderId() {
    return this.orderId;
  }

  @JsonProperty("order-id")
  public void setOrderId(int orderId) {
    this.orderId = orderId;
  }
}
PersonImpl
@JsonIgnoreProperties(ignoreUnknown=true)
class PersonImpl implements Person {
  private String name;
  private Collection<Order> orders;

  public String getName() {
    return this.name;
  }

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

  @JsonTypeInfo(use=JsonTypeInfo.Id.NONE, defaultImpl=OrderImpl.class)
  public Collection<Order> getOrders() {
    return this.orders;
  }

  @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, defaultImpl=OrderImpl.class)
  public void setOrders(Collection<Order> orders) {
    this.orders = orders;
  }
}

そして、最後に Person のファクトリを作成してやればプログラムは完成だ。

PersonFactory.java
public class PersonFactory {
  public Person fromJson(String jsonText) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    return mapper.readValue(jsonText, PersonImpl.class);
  }
}

PersonFactory クラスを使って、実際にデシリアライズする例は:

例-3
String jsonText = "{\"name\":\"sunny4381\",\"orders\":[{ \"order-id\":480310 },{ \"order-id\":480320 }],\"extra-member\":\"mem\"}";
PersonFactory factory = new PersonFactory();
Person person = factory.fromJson(jsonText);
System.out.println(person.getName());
48
41
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
41