Disons que je passe un appel à une API qui répond avec le JSON suivant pour un produit:
{
"id": 123,
"name": "The Best Product",
"brand": {
"id": 234,
"name": "ACME Products"
}
}
Je suis capable de mapper l'identifiant et le nom du produit très bien en utilisant les annotations 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;
}
}
Et puis en utilisant la méthode fromJson pour créer le produit:
JsonNode apiResponse = api.getResponse();
Product product = Json.fromJson(apiResponse, Product.class);
Mais maintenant, j'essaie de comprendre comment saisir le nom de la marque, qui est une propriété imbriquée. J'espérais que quelque chose comme ça fonctionnerait:
@JsonProperty("brand.name")
public String getBrandName() {
return brandName;
}
Mais bien sûr, non. Existe-t-il un moyen simple d'accomplir ce que je veux en utilisant des annotations?
La réponse JSON que j'essaie d'analyser est très complexe et je ne veux pas avoir à créer une nouvelle classe entière pour chaque sous-nœud, même si je n'ai besoin que d'un seul champ.
Réponses:
Vous pouvez réaliser ceci comme ça:
String brandName; @JsonProperty("brand") private void unpackNameFromNestedObject(Map<String, String> brand) { brandName = brand.get("name"); }
la source
this.abbreviation = ((Map<String, Object>)portalCharacteristics.get("icon")).get("ticker").toString();
Voici comment j'ai géré ce problème:
Brand
classe:package org.answer.entity; public class Brand { private Long id; private String name; public Brand() { } //accessors and mutators }
Product
classe: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 }
Ici, l'
brand
instance sera ignorée parJackson
pendantserialization
etdeserialization
, puisqu'elle est annotée avec@JsonIgnore
.Jackson
utilisera la méthode annotée avec@JsonGetter
forserialization
de l'objet java dans leJSON
format. Donc, lebrandName
est défini avecbrand.getName()
.De même,
Jackson
utilisera la méthode annotée avec@JsonSetter
fordeserialization
ofJSON
format en objet java. Dans ce scénario, vous devrez instancierbrand
vous-même l' objet et définir saname
propriété à partir debrandName
.Vous pouvez utiliser
@Transient
l'annotation de persistance avecbrandName
, si vous souhaitez qu'elle soit ignorée par le fournisseur de persistance.la source
Vous pouvez utiliser des expressions JsonPath pour mapper des propriétés imbriquées. Je ne pense pas qu'il y ait de support officiel (voir ce numéro), mais il y a une implémentation non officielle ici: https://github.com/elasticpath/json-unmarshaller
la source
Le mieux est d'utiliser des méthodes de setter:
JSON:
... "coordinates": { "lat": 34.018721, "lng": -118.489090 } ...
La méthode setter pour lat ou lng ressemblera à:
@JsonProperty("coordinates") public void setLng(Map<String, String> coordinates) { this.lng = (Float.parseFloat(coordinates.get("lng"))); }
si vous avez besoin de lire les deux (comme vous le feriez normalement), utilisez une méthode personnalisée
@JsonProperty("coordinates") public void setLatLng(Map<String, String> coordinates){ this.lat = (Float.parseFloat(coordinates.get("lat"))); this.lng = (Float.parseFloat(coordinates.get("lng"))); }
la source
Pour faire simple ... j'ai écrit le code ... la plupart est explicite.
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]]
la source
Bonjour, voici le code de travail complet.
// CLASSE DE TEST JUNIT
classe publique 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 de junit testcase
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
Essentiel complet: https://gist.github.com/jeorfevre/7c94d4b36a809d4acf2f188f204a8058
la source