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