Java

Java Jackson 操作JSON

<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 这两个标注通常配对使用, 通常用在父子关系中;

  1. @JsonBackReference 标注的属性在序列化(serialization, 即将对象转换为json数据)时, 会被忽略(即结果中的json数据不包含该属性的内容)

  2. @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

参考

  1. 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.

  1. 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

  1. 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

  1. 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)

JSON path 表达式

https://github.com/alibaba/fastjson/wiki/JSONPath