我想反序列化以下形式的类:
public class TestFieldEncryptedMessage implements ITextMessage {
@JsonProperty("text")
@Encrypted(cipherAlias = "testAlias")
private String text;
public TestFieldEncryptedMessage() {
}
@JsonCreator
public TestFieldEncryptedMessage(@JsonProperty("text") String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
在加密文本的地方,反序列化应该在重建TestFieldEncryptedMessage实例之前取消加密该值。
我遵循的方法非常类似于:https://github.com/codesqueak/jackson-json-crypto
也就是说,我正在构建一个扩展SimpleModule的模块:
public class CryptoModule extends SimpleModule {
public final static String GROUP_ID = "au.com.auspost.messaging";
public final static String ARTIFACT_ID = "jackson-json-crypto";
private EncryptedSerializerModifier serializerModifier;
private EncryptedDeserializerModifier deserializerModifier;
public CryptoModule() {
}
public CryptoModule addEncryptionService(final EncryptionService encryptionService) {
serializerModifier = new EncryptedSerializerModifier(encryptionService);
deserializerModifier = new EncryptedDeserializerModifier(encryptionService);
return this;
}
@Override
public String getModuleName() {
return ARTIFACT_ID;
}
@Override
public Version version() {
return new Version(major, minor, patch, null, GROUP_ID, ARTIFACT_ID);
}
@Override
public void setupModule(final SetupContext context) {
if ((null == serializerModifier) || (null == deserializerModifier))
throw new EncryptionException("Crypto module not initialised with an encryption service");
context.addBeanSerializerModifier(serializerModifier);
context.addBeanDeserializerModifier(deserializerModifier);
}
}
如您所见,设置了两个修饰符:EncryptedSerializerModifier可以正常工作并由ObjectMapper调用,但是EncryptedDeserializerModifier背后的反序列化器将被忽略。
在SO的许多其他示例中都可以看到,例如:How can I include raw JSON in an object using Jackson?,我使用以下命令设置了EncryptedDeserializerModifier:
public class EncryptedDeserializerModifier extends BeanDeserializerModifier {
private final EncryptionService encryptionService;
private Map<String, SettableBeanProperty> properties = new HashMap<>();
public EncryptedDeserializerModifier(final EncryptionService encryptionService) {
this.encryptionService = encryptionService;
}
@Override
public BeanDeserializerBuilder updateBuilder(final DeserializationConfig config, final BeanDescription beanDescription, final BeanDeserializerBuilder builder) {
Encrypted annotation = beanDescription.getType().getRawClass().getAnnotation(Encrypted.class);
Iterator it = builder.getProperties();
while (it.hasNext()) {
SettableBeanProperty p = (SettableBeanProperty) it.next();
if (null != p.getAnnotation(Encrypted.class)) {
JsonDeserializer<Object> current = p.getValueDeserializer();
properties.put(p.getName(), p);
builder.addOrReplaceProperty(p.withValueDeserializer(new EncryptedJsonDeserializer(encryptionService, current, p)), true);
}
}
return builder;
}
}
最后,EncryptedJsonDeserializer本身将覆盖以下内容:
@Override
public Object deserialize(final JsonParser parser, final DeserializationContext context) throws JsonMappingException {
JsonDeserializer<?> deserializer = baseDeserializer;
if (deserializer instanceof ContextualDeserializer) {
deserializer = ((ContextualDeserializer) deserializer).createContextual(context, property);
}
return service.decrypt(parser, deserializer, context, property != null ? property.getType() : type);
}
@Override
public JsonDeserializer<?> createContextual(final DeserializationContext context, final BeanProperty property) throws JsonMappingException {
JsonDeserializer<?> wrapped = context.findRootValueDeserializer(property.getType());
return new EncryptedJsonDeserializer(service, wrapped, property);
}
调用createContextual()方法,但不调用反序列化方法。在整个执行过程中,该属性始终是“文本”属性,因此我似乎具有正确的上下文。
有人知道为什么ObjectMapper找不到正确的反序列化器吗?
编辑将implements ITextMessage
添加到了解密的类中,我认为这是一个不重要的细节,但事实证明是造成该问题的原因。
答案 0 :(得分:1)
我发现了问题!如果仔细查看TestFieldEncryptedMessage
类,其text
字段是加密的,则可以看到它实现了一个接口。使用该接口是为了使消息为测试中的断言提供一些额外的工具,但是对于反序列化,则会产生意想不到的结果。我认为当ObjectMapper遍历json字符串时,它会尝试将反序列化器与ITextMessage
内的字段匹配,而不是TestFieldEncryptedMessage
内的字段,这就是为什么自定义反序列化器被不被调用(text
中没有ITextMessage
字段)。
一旦我停止实现ITextMessage,就会调用自定义解串器。