2014-09-15 6 views
3

Итак, название в основном описывает то, что мне нужно. Скажем, фасоль сериализовать выглядит следующим образом:Jackson add custom field with hash другого поля

public class SomeBean { 
    public String someString; 
} 

Я хотел бы Джексон сериализовать экземпляр SomeBean как это:

{ 
    someString: '<the value>', 
    __hash_someString: '<a proprietary hash of <the value>>' 
} 

Эта функциональность должна быть общей. Я не хочу писать определенный сериализатор для SomeBean, потому что это должно произойти в нескольких местах. Невозможно добавить ' __hash_someString' к самому классу, потому что это будет загрязнять модель.

Реализация

Я хотел бы Джексон обработать боб обычно. Но когда он сталкивается с конкретной аннотацией ( @GenerateHash), он должен добавить другое поле к объекту, как раньше. Так что хотелось бы это:

public class SomeBean { 
    @GenerateHash 
    public String someString; 
} 

Дорога до сих пор

Есть много подобных тем, но ни один из них не пытаются что-то вроде этого. Я не занимаюсь внутренней работой Jackson Serialization, но кажется, что вы только получаете возможность модифицировать объект в целом. Я не нашел способа перехватить процесс сериализации поля, только значение этого поля.

Я попытался реализовать это с помощью BeanSerializerModifier, а также пробовал некоторые вещи с помощью @Serializer. Тем не менее, я обычно оказываюсь в бесконечном цикле.

Ресурсы Я консультировался являются (не ограничиваясь ими):

Короче Как я могу получить Джексон сериализовать

public class SomeBean { 
    @GenerateHash 
    public String someString; 

    public String unaffectedString; 
} 

к этому:

{ 
    someString: '<the value>', 
    __hash_someString: '<a proprietary hash of <the value>>', 
    unaffectedString: '<some value>' 
} 

ответ

5

Это довольно интересно. Я думаю, вы можете решить это с помощью BeanSerializerModifier.

Идея состоит в регистрации пользовательского сериализатора, который будет иметь доступ к исходному сериализатору bean, описанию свойства и значению объекта. Если свойство аннотируется аннотацией GenerateHash, то сериализатор выдаст дополнительное поле.Вот пример:

public class JacksonGenerateHash { 
    @Retention(RetentionPolicy.RUNTIME) 
    public static @interface GenerateHash { 
    } 

    public static class Bean { 
     @GenerateHash 
     public final String value; 

     public Bean(final String value) { 
      this.value = value; 
     } 
    } 

    private static class MyBeanSerializerModifier extends BeanSerializerModifier { 
     @Override 
     public JsonSerializer<?> modifySerializer(
       final SerializationConfig serializationConfig, 
       final BeanDescription beanDescription, 
       final JsonSerializer<?> jsonSerializer) { 
      return new HashGeneratingSerializer((JsonSerializer<Object>) jsonSerializer, null); 
     } 
    } 

    private static class HashGeneratingSerializer extends JsonSerializer<Object> 
      implements ContextualSerializer { 
     private final JsonSerializer<Object> serializer; 
     private final BeanProperty property; 

     public HashGeneratingSerializer(
       final JsonSerializer<Object> jsonSerializer, 
       final BeanProperty property) { 
      this.serializer = jsonSerializer; 
      this.property = property; 
     } 

     @Override 
     public void serialize(
       final Object o, 
       final JsonGenerator jsonGenerator, 
       final SerializerProvider serializerProvider) 
     throws IOException { 
      serializer.serialize(o, jsonGenerator, serializerProvider); 
      // if the generatehash is present the property must be set 
      if (property != null) { 
       jsonGenerator.writeNumberField("_hash_" + property.getName(), o.hashCode()); 
      } 
     } 
     // override this method to access the bean property 
     @Override 
     public JsonSerializer<?> createContextual(
       final SerializerProvider prov, final BeanProperty property) 
       throws JsonMappingException { 
      if (property != null && property.getAnnotation(GenerateHash.class) != null) { 
       return new HashGeneratingSerializer(serializer, property); 
      } 
      return serializer; 
     } 
    } 

    public static void main(String[] args) throws JsonProcessingException { 
     SimpleModule module = new SimpleModule(); 
     module.setSerializerModifier(new MyBeanSerializerModifier()); 
     ObjectMapper mapper = new ObjectMapper(); 
     mapper.registerModule(module); 
     System.out.println(mapper.writeValueAsString(new Bean("abc"))); 
    } 
} 

Выход:

{"value":"abc","_hash_value":96354} 
+0

работает как шарм! Спасибо. Думаю, я пропустил это, потому что мы работаем на более старой версии Jackson (2.0). Немедленно обновляется. – sdegroot