Java Jackson 操作JSON
- 参考: https://github.com/FasterXML/jackson-databind
- API: https://github.com/FasterXML/jackson-core/wiki
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>配置 ObjectMapper
private final static ObjectMapper MAPPER = new ObjectMapper();
static {
//序列化
MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //空字段不抛异常
MAPPER.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);//日期类型禁用 转为时间戳
DateFormat dateformat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
MAPPER.setDateFormat(dateformat);//设置时间格式
MAPPER.setSerializationInclusion(Include.NON_NULL); //序列化时忽略null
//反序列化
MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
MAPPER.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);//空 String 为 null
}解决双向关联序列化
@JsonBackReference和@JsonManagedReference 这两个标注通常配对使用, 通常用在父子关系中;
-
@JsonBackReference标注的属性在序列化(serialization, 即将对象转换为json数据)时, 会被忽略(即结果中的json数据不包含该属性的内容) -
@JsonManagedReference标注的属性则会被序列化;
在序列化时, @JsonBackReference的作用相当于@JsonIgnore, 此时可以没有@JsonManagedReference;
但在反序列化(deserialization, 即json数据转换为对象)时:
- 如果没有
@JsonManagedReference, 则不会自动注入@JsonBackReference标注的属性(被忽略的父或子); - 如果有
@JsonManagedReference, 则会自动注入自动注入@JsonBackReference标注的属性;
@JsonManagedReference 和 @JsonBackReference 总是成对出现的
in short @JsonBackReference在子对象注解 给父(obj), @JsonManagedReference在父对象注解 给子(list)
不能将 Collection, Map, Array or enumeration 用作
@JsonBackReference
带泛型序列化
//反序列 泛型List
public static <T> List<T> jsonToListBean(String jsonStr, Class<T> objClass){
JavaType typeT = MAPPER.getTypeFactory().constructParametricType(List.class, objClass);
try {
return MAPPER.readValue(jsonStr, typeT);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}//反序列 List<Map>
public static List<Map<String,Object>> jsonToListMapBean(String jsonStr){
JavaType typeT = MAPPER.getTypeFactory().constructParametricType(List.class, Map.class);
try {
return MAPPER.readValue(jsonStr, typeT);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}自定义序列化 (字段脱敏一则)
//JsonStringDesensitization.java 自定义序列化实现
public class JsonStringDesensitization extends JsonSerializer<String> implements ContextualSerializer{
private static final Logger log = LoggerFactory.getLogger(JsonStringDesensitization.class);
String maskingWord = "*";
int[] masking = {0, 8};
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
//创建上下文
StringSensitive stringSensitive = property.getAnnotation(StringSensitive.class);
if (stringSensitive != null) {
maskingWord = stringSensitive.maskingWord();
masking = stringSensitive.maskingIndexs();
}
return this ;
}
/* (non-Javadoc)
* @see com.fasterxml.jackson.databind.JsonSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
* @author yangfh
* @param value
* @param gen
* @param serializers
* @throws IOException
*/
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value==null) {
gen.writeString(value);
return;
}
int pre = masking[0];
int suf = masking[1];
if(pre > suf || value.length() < suf ) {
gen.writeString(value);
return;
}
String s = value.substring(0, pre);
String m = StrUtil.repeat(maskingWord, suf-pre);
String e = value.substring(suf, value.length());
gen.writeString(s+m+e);
return;
}
//StringSensitive.java 脱敏注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = JsonStringDesensitization.class)
public @interface StringSensitive {
String maskingWord() default "*";
int[] maskingIndexs() default {4, 8};
}
//UserDTO.java 使用
@Data
public class UserDTO implements Serializable {
private String name;
@StringSensitive
private String username;
} 大数据序列化
使用 core 的低级api
- Overview
In this article, we will be looking at the Jackson Streaming API. It supports both reading and writing, and by using it, we can write high-performance and fast JSON parsers.
On the flip-side, it is a bit difficult to use – every detail of JSON data needs to be handled explicitly in code.
- Maven Dependency Firstly, we need to add a Maven dependency to the jackson-core:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.1</version>
</dependency>Writing to JSON
- Writing to JSON We can write JSON content directly to the OutputStream by using a JsonGenerator class. Firstly, we need to create the instance of that object:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
JsonFactory jfactory = new JsonFactory();
JsonGenerator jGenerator = jfactory
.createGenerator(stream, JsonEncoding.UTF8);Next, let’s say that we want to write a JSON with the following structure:
{
"name":"Tom",
"age":25,
"address":[
"Poland",
"5th avenue"
]
}We can use an instance of the JsonGenerator to write specific fields directly to the OutputStream:
jGenerator.writeStartObject();
jGenerator.writeStringField("name", "Tom");
jGenerator.writeNumberField("age", 25);
jGenerator.writeFieldName("address");
jGenerator.writeStartArray();
jGenerator.writeString("Poland");
jGenerator.writeString("5th avenue");
jGenerator.writeEndArray();
jGenerator.writeEndObject();
jGenerator.close();
```java
//To check if proper JSON was created, we can create a String object with JSON object in it:
String json = new String(stream.toByteArray(), "UTF-8");
assertEquals(
```json,
"{\"name\":\"Tom\",\"age\":25,\"address\":[\"Poland\",\"5th avenue\"]}");Parsing JSON
- Parsing JSON
When we get a JSON String as an input, and we want to extract specific fields from it, a JsonParser class can be used:
String json = "{\"name\":\"Tom\",\"age\":25,\"address\":[\"Poland\",\"5th avenue\"]}";
JsonFactory jfactory = new JsonFactory();
JsonParser jParser = jfactory.createParser(json);
String parsedName = null;
Integer parsedAge = null;
List<String> addresses = new LinkedList<>();
We want to obtain parsedName, parsedAge, and addresses fields from input JSON. To achieve this, we need to handle low-level parsing logic and implement it ourselves:
while (jParser.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jParser.getCurrentName();
if ("name".equals(fieldname)) {
jParser.nextToken();
parsedName = jParser.getText();
}
if ("age".equals(fieldname)) {
jParser.nextToken();
parsedAge = jParser.getIntValue();
}
if ("address".equals(fieldname)) {
jParser.nextToken();
while (jParser.nextToken() != JsonToken.END_ARRAY) {
addresses.add(jParser.getText());
}
}
}
jParser.close();
Depending on the field name, we are extracting it and assigning to a proper field. After parsing the document, all fields should have correct data:
assertEquals(parsedName, "Tom");
assertEquals(parsedAge, (Integer) 25);
assertEquals(addresses, Arrays.asList("Poland", "5th avenue"));
使用ObjectMapper
太底层了, 要自己处理token, 其实 用ObjectMapper 也是可以的.
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(out, lsit);
/**
* Method that can be used to serialize any Java value as
* JSON output, using output stream provided (using encoding
* {@link JsonEncoding#UTF8}).
*<p>
* Note: method does not close the underlying stream explicitly
* here; however, {@link JsonFactory} this mapper uses may choose
* to close the stream depending on its settings (by default,
* it will try to close it when {@link JsonGenerator} we construct
* is closed).
*/
public void writeValue(OutputStream out, Object value)