Katakanlah saya melakukan panggilan ke API yang merespons dengan JSON berikut untuk sebuah produk:
{
"id": 123,
"name": "The Best Product",
"brand": {
"id": 234,
"name": "ACME Products"
}
}
Saya dapat memetakan id dan nama produk dengan baik menggunakan anotasi Jackson:
public class ProductTest {
private int productId;
private String productName, brandName;
@JsonProperty("id")
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
@JsonProperty("name")
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
}
Dan kemudian menggunakan metode fromJson untuk membuat produk:
JsonNode apiResponse = api.getResponse();
Product product = Json.fromJson(apiResponse, Product.class);
Tapi sekarang saya mencoba mencari cara untuk mendapatkan nama merek, yang merupakan properti bertingkat. Saya berharap sesuatu seperti ini akan berhasil:
@JsonProperty("brand.name")
public String getBrandName() {
return brandName;
}
Tapi tentu saja tidak. Adakah cara mudah untuk mencapai apa yang saya inginkan dengan menggunakan anotasi?
Respons JSON sebenarnya yang saya coba parse sangat kompleks, dan saya tidak ingin membuat seluruh kelas baru untuk setiap sub-node, meskipun saya hanya memerlukan satu bidang.
Jawaban:
Anda dapat mencapai ini seperti itu:
String brandName; @JsonProperty("brand") private void unpackNameFromNestedObject(Map<String, String> brand) { brandName = brand.get("name"); }
sumber
this.abbreviation = ((Map<String, Object>)portalCharacteristics.get("icon")).get("ticker").toString();
Beginilah cara saya menangani masalah ini:
Brand
kelas:package org.answer.entity; public class Brand { private Long id; private String name; public Brand() { } //accessors and mutators }
Product
kelas:package org.answer.entity; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSetter; public class Product { private Long id; private String name; @JsonIgnore private Brand brand; private String brandName; public Product(){} @JsonGetter("brandName") protected String getBrandName() { if (brand != null) brandName = brand.getName(); return brandName; } @JsonSetter("brandName") protected void setBrandName(String brandName) { if (brandName != null) { brand = new Brand(); brand.setName(brandName); } this.brandName = brandName; } //other accessors and mutators }
Di sini,
brand
instance akan diabaikan olehJackson
selamaserialization
dandeserialization
, karena dianotasi dengan@JsonIgnore
.Jackson
akan menggunakan metode yang dianotasi@JsonGetter
untukserialization
objek java ke dalamJSON
format. Jadi,brandName
disetel denganbrand.getName()
.Demikian pula,
Jackson
akan menggunakan metode yang dianotasi dengan@JsonSetter
fordeserialization
dariJSON
format ke objek java. Dalam skenario ini, Anda harus membuatbrand
sendiri objek tersebut dan menyetelname
propertinya daribrandName
.Anda dapat menggunakan
@Transient
anotasi persistensi denganbrandName
, jika ingin diabaikan oleh penyedia persistensi.sumber
Anda bisa menggunakan ekspresi JsonPath untuk memetakan properti bertingkat. Saya tidak berpikir ada dukungan resmi (lihat masalah ini ), tetapi ada implementasi tidak resmi di sini: https://github.com/elasticpath/json-unmarshaller
sumber
Yang terbaik adalah menggunakan metode penyetel:
JSON:
... "coordinates": { "lat": 34.018721, "lng": -118.489090 } ...
metode penyetel untuk lat atau lng akan terlihat seperti:
@JsonProperty("coordinates") public void setLng(Map<String, String> coordinates) { this.lng = (Float.parseFloat(coordinates.get("lng"))); }
jika Anda perlu membaca keduanya (seperti yang biasa Anda lakukan), gunakan metode khusus
@JsonProperty("coordinates") public void setLatLng(Map<String, String> coordinates){ this.lat = (Float.parseFloat(coordinates.get("lat"))); this.lng = (Float.parseFloat(coordinates.get("lng"))); }
sumber
Untuk membuatnya sederhana .. Saya telah menulis kodenya ... sebagian besar sudah cukup jelas.
Main Method
package com.test; import java.io.IOException; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; public class LOGIC { public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException { ObjectMapper objectMapper = new ObjectMapper(); String DATA = "{\r\n" + " \"id\": 123,\r\n" + " \"name\": \"The Best Product\",\r\n" + " \"brand\": {\r\n" + " \"id\": 234,\r\n" + " \"name\": \"ACME Products\"\r\n" + " }\r\n" + "}"; ProductTest productTest = objectMapper.readValue(DATA, ProductTest.class); System.out.println(productTest.toString()); } }
Class ProductTest
package com.test; import com.fasterxml.jackson.annotation.JsonProperty; public class ProductTest { private int productId; private String productName; private BrandName brandName; @JsonProperty("id") public int getProductId() { return productId; } public void setProductId(int productId) { this.productId = productId; } @JsonProperty("name") public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } @JsonProperty("brand") public BrandName getBrandName() { return brandName; } public void setBrandName(BrandName brandName) { this.brandName = brandName; } @Override public String toString() { return "ProductTest [productId=" + productId + ", productName=" + productName + ", brandName=" + brandName + "]"; } }
Class BrandName
package com.test; public class BrandName { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "BrandName [id=" + id + ", name=" + name + "]"; } }
OUTPUT
ProductTest [productId=123, productName=The Best Product, brandName=BrandName [id=234, name=ACME Products]]
sumber
Hai, ini kode kerja lengkap.
// KELAS TES JUNIT
kelas publik sof {
@Test public void test() { Brand b = new Brand(); b.id=1; b.name="RIZZE"; Product p = new Product(); p.brand=b; p.id=12; p.name="bigdata"; //mapper ObjectMapper o = new ObjectMapper(); o.registerSubtypes(Brand.class); o.registerSubtypes(Product.class); o.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); String json=null; try { json = o.writeValueAsString(p); assertTrue(json!=null); logger.info(json); Product p2; try { p2 = o.readValue(json, Product.class); assertTrue(p2!=null); assertTrue(p2.id== p.id); assertTrue(p2.name.compareTo(p.name)==0); assertTrue(p2.brand.id==p.brand.id); logger.info("SUCCESS"); } catch (IOException e) { e.printStackTrace(); fail(e.toString()); } } catch (JsonProcessingException e) { e.printStackTrace(); fail(e.toString()); } } } **// Product.class** public class Product { protected int id; protected String name; @JsonProperty("brand") //not necessary ... but written protected Brand brand; } **//Brand class** public class Brand { protected int id; protected String name; }
//Console.log dari testcase junit
2016-05-03 15:21:42 396 INFO {"id":12,"name":"bigdata","brand":{"id":1,"name":"RIZZE"}} / MReloadDB:40 2016-05-03 15:21:42 397 INFO SUCCESS / MReloadDB:49
Inti lengkap: https://gist.github.com/jeorfevre/7c94d4b36a809d4acf2f188f204a8058
sumber