2017-10-20 17 views
0

J'essaye d'implémenter un Jackson Deserializer pour avoir un moyen de migrer des JSON quand ils changent (comme un champ renommé, par exemple, où je devrais lire un JSON maintenant incohérent en un cohérent). Une façon de le faire serait de créer un JsonDeserializer, de lire le JSON comme la classe finale appropriée, puis de le lire à nouveau comme un MAP, afin de sélectionner les modifications.Désérialisation personnalisée de Jackson - impossible de lire deux fois JsonParser

Je ne peux pas sembler faire cela parce que, chaque fois que je lis ou désérialise le JSON, le flux de sauvegarde se ferme.

class CustomDeserializer extends StdDeserializer<MyPOJO> implements ResolvableDeserializer{ 

    private final JsonDeserializer<?> deserializer; 
    private final ObjectMapper mapper; 

    public CustomDeserializer(JsonDeserializer<?> deserializer, ObjectMapper mapper) { 
     super(MyPOJO.class); 
     this.deserializer = deserializer; 
     this.mapper = mapper; 
    } 

    @Override 
    public MyPOJO deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     MyPOJO deserialized = (MyPOJO) deserializer.deserialize(jp, ctxt); 
     // Custom migration would go here... 
     return deserialized; 
    } 

    @Override 
    public void resolve(DeserializationContext ctxt) throws JsonMappingException { 
     ((ResolvableDeserializer) deserializer).resolve(ctxt); 
    } 
} 

J'évite la création de nouvelles ObjectMapper parce qu'il ya déjà un sur mesure, avec une coutume date désérialiseur, par exemple, quand je me sers MyPOJO désérialiseur personnalisé Je veux être en mesure de déléguer en quelque sorte le désérialisation dans certains manière de sorte qu'il utilise toute la configuration précédente.

Répondre

0

C'est ce que je suis venu avec:

@Autowired 
    public Serializer(List<IDeserializer> deserializers) { 
     SimpleModule module = new SimpleModule("name"); 
     registerDeserializers(module, deserializers); 
     mapper.registerModule(module); 
     mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true); 
     mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 
     mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd")); 
    } 

    private void registerDeserializers(SimpleModule module, List<IDeserializer> deserializers) { 
     if (CollectionUtils.isNotEmpty(deserializers)) { 
      final Map<Class<?>, IDeserializer> deserializerRegistryMap = toMap(deserializers); 
      module.setDeserializerModifier(new BeanDeserializerModifier() { 
       @Override 
       public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) { 
        if (deserializerRegistryMap.containsKey(beanDesc.getBeanClass())){ 
         return deserializerRegistryMap.get(beanDesc.getBeanClass()).getDeserializer(mapper); 
        } 
        return super.modifyDeserializer(config, beanDesc, deserializer); 
       } 
      }); 
     } 
    } 


@Component 
public class MigrationDeserializer { 

    @Autowired 
    private MigratorRegistry migratorRegistry; 

    public <T> JsonDeserializer<T> createDeserializer(final ObjectMapper mapper, final Class<T> returnType, final Class<? extends SerializedObjectsHistory<T>> historyType){ 
     return new StdDeserializer<T>(returnType){ 

      @Override 
      public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
       SerializedObjectsHistory<T> history = mapper.readValue(p, historyType); 
       return migratorRegistry.migrate(history, returnType); 
      } 
     }; 
    } 
} 

Sur les serializers je désérialisation mon POJO dans « HistoryPOJO » qui est essentiellement la même chose que mon POJO, mais avec tous les champs, même enlevés/rebaptisées ceux

Ensuite, je le transforme en la version actuelle.