Jackson
是Java平台很是流行的JSON解析框架,并且扩展性很强,本文经过添加一个Module来增强JSON字段的解析来实现单个字段的加密与解密功能。java
基本想法是使用Jackson
来处理自定义的注解,在须要加密/解密的字段上添加上相应的注解,先定义个自定义的注解:git
@JacksonAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface Encrypt {}
复制代码
而后在须要在POJO中对字段添加@Encrypt
注解:github
public final class User {
@Encrypt
private String name;
private String guid;
@Encrypt
private User first;
@Encrypt
private int age;
//... getters/setters
}
复制代码
完成上面的工做后,而后再来扩展Jackson
来处理@Encrypt
注解进行字段加密,先定义个Jackson
的Module:json
public class EncryptionModule extends Module {
public final static String ARTIFACT_ID = "jackson-hb-encryption";
public final static Version VERSION = new Version(1, 0, 0, null);
private EncryptionModule(){
}
...
@Override
public void setupModule(SetupContext setupContext) {
setupContext.addBeanSerializerModifier(new EncryptedSerializerModifier());
setupContext.addBeanDeserializerModifier(new EncryptedDeserializerModifier());
}
/** * 建立一个{@link ObjectMapper}对象,支持{@link Encrypt}注解。 * @return */
public static ObjectMapper createMapper(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure( SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.registerModule(new EncryptionModule());
return objectMapper;
}
}
复制代码
建立module只须要继承org.codehaus.jackson.map.Module
类,EncryptionModule
在setupModule
方法中添加了一个序列化修改器和反序列化修改器,EncryptedSerializerModifier
重载changeProperties
方法,遍历属性若是属性有@Encrypt
注解那么须要将属性的JsonSerializer
设置为EncryptedJsonSerializer
。app
public class EncryptedSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BasicBeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
/* 遍历beanProperties处理Encrypt.class注解 */
List<BeanPropertyWriter> newWriter = new ArrayList<>();
for(BeanPropertyWriter writer : beanProperties){
if(null == writer.getAnnotation(Encrypt.class)){
newWriter.add(writer);
}else{
JsonSerializer<Object> serializer = new EncryptedJsonSerializer(writer.getSerializer());
newWriter.add(writer.withSerializer(serializer));
}
}
return newWriter;
}
}
复制代码
EncryptedJsonSerializer
是自定义的序列化工具,它实现属性字段的加密功能:框架
public class EncryptedJsonSerializer extends JsonSerializer<Object> {
/** * 默认序列化工具对象 */
private final JsonSerializer<Object> serializer;
public EncryptedJsonSerializer(JsonSerializer<Object> serializer) {
this.serializer = serializer;
}
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
StringWriter stringWriter = new StringWriter();
ObjectCodec objectCodec = jsonGenerator.getCodec();
JsonGenerator nestedGenerator = null;
//空对象或空字符串不处理。
if(o == null || Strings.isNullOrEmpty(String.valueOf(o))){
if (serializer == null) {
serializerProvider.defaultSerializeValue(o, jsonGenerator);
}else{
serializer.serialize(o, jsonGenerator, serializerProvider);
}
return;
}
/* 生成一个新的JsonGenerator,用于将o写入。 */
if(objectCodec instanceof ObjectMapper){
nestedGenerator = ((ObjectMapper) objectCodec).getJsonFactory().createJsonGenerator(stringWriter);
}
if (nestedGenerator == null) {
throw new NullPointerException("nestedGenerator == null");
}
/* 将数据写入到新生成的JsonGenerator中 */
if (serializer == null) {
serializerProvider.defaultSerializeValue(o, nestedGenerator);
}else{
serializer.serialize(o, nestedGenerator, serializerProvider);
}
nestedGenerator.close();
/* JsonGenerator会生成一个带双引号的字符串, 将数据加密后写入。 */
String value = stringWriter.getBuffer().toString();
try {
//空字符串不加密
jsonGenerator.writeString(AESTools.encrypt(value));
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
复制代码
EncryptedJsonSerializer
的处理是先判断是否为空对象或空字符串,若是是那就将它们直接收入到jsonGenerator
,不然的话建立一个新的nestedGenerator
并将数据写入进去,而后再拿出来进行AES加密,最后写入到原始的jsonGenerator
中,这样就完成了属性的加密以久序列化工做。ide