Learning jackson

JS number type accuracy problem

In js number type is 53 bit, if backgroud response 64 bit long type,
js will lose accuracy, number will not be the origin number.

53 bit in decimal system length is about 16(2^52),but in java long type is about 20(2^64).
So backgroud return type in string is a better choice to void accuracy problem.

JsonSerializer JsonDeserializer

Avoiding JS loss of accuracy

1
2
3
4
5
6
7
8
public class LongJsonSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
String text = (value == null ? null : String.valueOf(value));
if (text != null)
jsonGenerator.writeString(text);
}
}

Deserialize input model

1
2
3
4
5
6
7
8
9
10
11
12
13
@Slf4j
public class LongJsonDeserializer extends JsonDeserializer<Long> {
@Override
public Long deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
String value = jsonParser.getText();
try {
return value == null ? null : Long.parseLong(value);
} catch (NumberFormatException e) {
log.error("Deserialize long type error: {}", value);
return null;
}
}
}

Annotate the target property

1
2
3
@JsonSerialize(using = LongJsonSerializer.class)
@JsonDeserialize(using = LongJsonDeserializer.class)
private Long id;

Data Binding [Commonly used]

Maven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>

Model

1
2
3
4
5
6
7
@Data
public class Country {
private Integer id;
private String countryName;
private List<Province> provinces;
private String[] lakes;
}
1
2
3
4
5
6
@Data
public class Province {
private Integer id;
private String provinceName;
private List<City> cities;
}
1
2
3
4
5
6
7
@Data
@AllArgsConstructor
@NoArgsConstructor
public class City {
private Integer id;
private String cityName;
}

Bean2JsonStr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Test
public void Bean2JsonStr() throws IOException {
// Convert the object to Json
ObjectMapper mapper = new ObjectMapper();
// set format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
City city1 = new City(1, "hangzhou");
City city2 = new City(2, "taizhou");

Province province = new Province();
province.setId(1);
List<City> cities = new ArrayList<City>();
cities.add(city1);
cities.add(city2);
province.setCities(cities);

Country country = new Country();
country.setCountryName("China");
country.setId(1);
country.setLakes(new String[]{"Qinghai Lake", "Poyang Lake", "Dongting Lake", "Taihu Lake"});
List<Province> provinces = new ArrayList<Province>();
provinces.add(province);
country.setProvinces(provinces);
// set true make json readable, no need in produce environment
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
// ignore null property
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
// java property as key in default, customize key name in @JsonProperty annotation
mapper.writeValue(new File("country-demo.json"), country);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"id" : 1,
"countryName" : "China",
"provinces" : [ {
"id" : 1,
"cities" : [ {
"id" : 1,
"cityName" : "hangzhou"
}, {
"id" : 2,
"cityName" : "taizhou"
} ]
} ],
"lakes" : [ "Qinghai Lake", "Poyang Lake", "Dongting Lake", "Taihu Lake" ]
}

JsonStr2Bean

string -> object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void JsonStr2Bean() throws IOException {
ObjectMapper mapper = new ObjectMapper();
File jsonFile = new File("country-demo.json");
// not interrupt unknown properties
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
Country country = mapper.readValue(jsonFile, Country.class);

log.info(country.getCountryName());
List<Province> provinces = country.getProvinces();
for (Province province : provinces) {
for (City city : province.getCities()) {
log.info(city.getId() + " " + city.getCityName());
}
}
}

1
2
3
09:52:05.570 [main] INFO jackson.JacksonDemoTester - China
09:52:05.574 [main] INFO jackson.JacksonDemoTester - 1 hangzhou
09:52:05.575 [main] INFO jackson.JacksonDemoTester - 2 taizhou

JsonStr2List

string -> list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void JsonStr2List() throws IOException {
City city1 = new City(1, "hangzhou");
City city2 = new City(2, "taizhou");

List<City> cities = new ArrayList<>();
cities.add(city1);
cities.add(city2);

ObjectMapper mapper = new ObjectMapper();
String listJsonStr = mapper.writeValueAsString(cities);
log.info(listJsonStr);
List<City> list = mapper.readValue(listJsonStr, new TypeReference<List<City>>() {});
for (City city : list) {
log.info("id:" + city.getId() + " cityName:" + city.getCityName());
}
}

1
2
3
09:52:15.610 [main] INFO jackson.JacksonDemoTester - China
09:52:15.612 [main] INFO jackson.JacksonDemoTester - 1 hangzhou
09:52:15.613 [main] INFO jackson.JacksonDemoTester - 2 taizhou

Streaming API [high performence]

self define paser

JsonSerializer

1
2
3
4
5
6
7
8
9
10
public class CityJsonSerializer extends JsonSerializer<City> {
@Override
public void serialize(City city, JsonGenerator jsonGenerator, SerializerProvider arg2) throws IOException {
jsonGenerator.writeStartObject();
if ( city.getId()!=null)
jsonGenerator.writeNumberField("id", city.getId());
jsonGenerator.writeStringField("cityName", city.getCityName());
jsonGenerator.writeEndObject();
}
}

JsonDeserializer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Slf4j
public class CityJsonDeserializer extends JsonDeserializer<List<City>> {

@Override
public List<City> deserialize(JsonParser parser, DeserializationContext deserializationcontext) throws IOException {
List<City> list = new ArrayList<>();
// deserialize array, fist token must be JsonToken.START_ARRAY '['
if (!JsonToken.START_ARRAY.equals(parser.getCurrentToken())) {
log.info(parser.getCurrentToken().asString());
return null;
}
// until the EOF
while (!parser.isClosed()) {
// loop until the target token
JsonToken token = parser.nextToken();
if (token == null) break;
// every element in array is object, so the nect JsonToken is JsonToken.START_OBJECT '{'
if (!JsonToken.START_OBJECT.equals(token)) break;

City city = null;
while (true) {
if (JsonToken.START_OBJECT.equals(token))
city = new City();

token = parser.nextToken();
if (token == null) break;

if (JsonToken.FIELD_NAME.equals(token)) {
if ("id".equals(parser.getCurrentName())) {
token = parser.nextToken();
city.setId(parser.getIntValue());
} else if ("cityName".equals(parser.getCurrentName())) {
token = parser.nextToken();
city.setCityName(parser.getText());
}
}
if (JsonToken.END_OBJECT.equals(token))
list.add(city);
}
}
return list;
}
}

StreamJsonStr2List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Test
public void StreamJsonStr2List() throws IOException {
City city1 = new City();
city1.setCityName("hangzhou");
City city2 = new City(2, "taizhou");

List<City> cities = new ArrayList<>();
cities.add(city1);
cities.add(city2);

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(City.class, new CityJsonSerializer());
mapper.registerModule(module);
String listJsonStr = mapper.writeValueAsString(cities);

log.info(listJsonStr);

ObjectMapper mapper2 = new ObjectMapper();
SimpleModule module2 = new SimpleModule();
module2.addDeserializer(List.class, new CityJsonDeserializer());
mapper2.registerModule(module2);
List<City> list = mapper2.readValue(listJsonStr, new TypeReference<List<City>>() {});

for (City city : list) {
log.info("id:" + city.getId() + " cityName:" + city.getCityName());
}
}
1
2
3
10:15:03.874 [main] INFO jackson.JacksonDemoTester - [{"cityName":"hangzhou"},{"id":2,"cityName":"taizhou"}]
10:15:03.889 [main] INFO jackson.JacksonDemoTester - id:null cityName:hangzhou
10:15:03.889 [main] INFO jackson.JacksonDemoTester - id:2 cityName:taizhou

use annotation to avoid module in code

1
2
3
4
@JsonSerialize(using=CityJsonSerializer.class)
public class City {
...
}

Tree Model [flexible]

TreeMode2Json

no java class/ pojo, create model by tree model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Test
public void TreeMode2Json() throws IOException {

// create a factory provide node
JsonNodeFactory factory = new JsonNodeFactory(false);
// create a factory to convert tree model to json
JsonFactory jsonFactory = new JsonFactory();
//create a json generator
JsonGenerator generator = jsonFactory.createGenerator(new FileWriter(new File("country-demo2.json")));

ArrayNode cities = factory.arrayNode();
cities.add(factory.objectNode().put("id", 1).put("cityName", "hangzhou"))
.add(factory.objectNode().put("id", 2).put("cityName", "taizhou"));

ArrayNode provinces = factory.arrayNode();
ObjectNode province = factory.objectNode();
province.put("cities", cities);
province.put("provinceName", "zhejiang");
provinces.add(province);

ObjectNode country = factory.objectNode();
country.put("id", 1).put("countryName", "China");
country.put("provinces", provinces);

// caution! in default mapper not set root node
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
mapper.writeTree(generator, country);
}

TreeModeReadJson

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void TreeModeReadJson() throws IOException{
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(new File("country-demo2.json"));
// show node type
log.info("node JsonNodeType:"+node.getNodeType());
log.info("----------------sub node name----------------------");
Iterator<String> fieldNames = node.fieldNames();
while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
log.info(fieldName+" ");
}
log.info("---------------------------------------------------");
}
1
2
3
4
5
6
10:58:44.995 [main] INFO jackson.JacksonDemoTester - node JsonNodeType:OBJECT
10:58:44.999 [main] INFO jackson.JacksonDemoTester - ----------------sub node name----------------------
10:58:44.999 [main] INFO jackson.JacksonDemoTester - id
10:58:44.999 [main] INFO jackson.JacksonDemoTester - countryName
10:58:44.999 [main] INFO jackson.JacksonDemoTester - provinces
10:58:45.000 [main] INFO jackson.JacksonDemoTester - ---------------------------------------------------

https://www.cnblogs.com/lvgg/p/7475140.html
https://www.cnblogs.com/williamjie/p/9242451.html
https://blog.csdn.net/gjb724332682/article/details/51586701
https://blog.csdn.net/java_huashan/article/details/46375857