2017-09-19 4 views
2

私はMap<String, Object>の形でDBから結果セットを得ました。これは、RESTサービスからjsonとして返さなければなりません。地図内の値は、PGObject,String,IntegerおよびDateなどのさまざまな種類の値を取ることができます。Map <String、Object>にJacksonカスタム値シリアライザを使用する方法

List<?>では正常に動作しますが、Map<String, Object>では正しく動作しないタイプ "jsonb"のorg.postgresql.util.PGObjectクラスのカスタムシリアライザを作成しました。

public class PgObjectSerializer extends JsonSerializer<PGobject>{ 

    @Override 
    public void serialize(PGobject pgObject, JsonGenerator gen, SerializerProvider serializers) throws IOException { 
     switch (pgObject.getType()) { 
      case "json": 
      case "jsonb": 
       gen.writeRawValue(pgObject.getValue()); 
       break; 
      default: 
       gen.writeString(pgObject.getValue()); 
     } 
    } 
} 

ターゲットのpgobjectは次のようになります。

PGObject pgo = new PGObject(); 
pgo.setType("jsonb"); 
pgo.setValue("[{"id": 6, "name": "Foo"}, {"id": 7, "name": "Bar"}, {"id": 8, "name": "Baz"}]"); map.put("reason", pgo); 

ジャクソンはMap<String, Object>にこのPGObject値をシリアライズするとき、私は同じようjson値を取得:私は必要なもの

"reason": { 
    "type": "jsonb", 
    "value": "[{\"id\": 6, \"name\": \"Foo\"}, {\"id\": 7, \"name\": \"Bar\"}, {\"id\": 8, \"name\": \"Baz\"}]" 
    } 

"reason": [ 
    { 
     "id": 6, 
     "name": "Foo" 
    }, 
    { 
     "id": 7, 
     "name": "Bar" 
    }, 
    { 
     "id": 8, 
     "name": "Baz" 
    }, 
    ], 

Serializing Map<Date, String> with Jacksonへの回答で示したように、私はObjectMapperObjectWriterにカスタムMapTypeにモジュールを追加しようとしました:

@Service 
@Transactional 
public class MyClass { 
    private final ObjectWriter writer; 
    private final MyRepo repository; 

    @Autowired 
    public MyClass(MyRepo repository) { 
     this.repository = repository; 

     SimpleModule module = new SimpleModule(); 
     module.addKeySerializer(PGobject.class, new PgObjectSerializer()); 

     ObjectMapper mapper = new ObjectMapper(); 
     JavaType myMapType = mapper.getTypeFactory(). 
       constructMapType(HashMap.class, String.class, PGobject.class); 
     writer = mapper.registerModule(module).writerFor(myMapType); 
    } 

    ... 

    private String toJsonString(Map<String, Object> map) { 
     try { 
      return writer.writeValueAsString(map); 
     } catch (JsonProcessingException e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

が、私はマップ内のすべての非PGObjectオブジェクトの直列化エラーを取得:

[Test worker] ERROR 
com.fasterxml.jackson.databind.JsonMappingException: object is not an instance of declaring class (through reference chain: java.util.HashMap["end_date"]->java.lang.String["type"]) 
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388) 
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348) 
    at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:343) 
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:698) 
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) 
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFieldsUsing(MapSerializer.java:736) 
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:534) 
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:30) 
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:416) 
    at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1425) 
    at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1158) 
    at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1031) 

Map<String, Object>のシリアル化中にPGObjectが値として見つかった場合、Jacksonの私のPGObjectSerializerを有効にするにはどうすればいいですか?

+0

ではなくaddKeySerializerのmodule.addSerializer()を使用してみてください。私はキーシリアライザはキーのためだけに働くと思う。 –

+0

@ oleg.cherednik、これを指摘してくれてありがとう、それが理由でした!私は 'addSerializer'に変更しました。そして、私のコードは完全に正常に動作します。 – Rodion

答えて

0

Objectのシリアライザを追加することができます。

次に、シリアライザ自体で、ObjectがinstanceOfであるかどうかを確認することができますPGobject

とmyMapTypeにあなたがObject.classを指定することができます。

JavaType myMapType = mapper.getTypeFactory(). 
       constructMapType(HashMap.class, String.class, Object.class); 

シリアライザは、次のようになります。

class PgObjectSerializer extends JsonSerializer<Object> { 
@Override 
public void serialize(Object object, JsonGenerator gen, SerializerProvider serializers) throws IOException { 
    if (object instanceof PGobject) { 
     PGobject pgObject = (PGobject) object; 
     switch (pgObject.getType()) { 
     case "json": 
     case "jsonb": 
       gen.writeRawValue(pgObject.getType()); 
       break; 
     default: 
       gen.writeString(pgObject.getType()); 
     } 
     }else{ 
       ObjectMapper mapper = new ObjectMapper(); 
       mapper.writeValue(gen, object); 
     } 
    } 
} 
+0

この回避策では、他のすべてのクラス型のシリアル化を他の「ベース」シリアライザまたは「汎用」シリアライザに委任する必要があります。私はそのようなものを見つけませんでした。 – Rodion

+0

obejctマッパーを使用することができます。更新されたPgObjectSerializer –

+0

残念ながら、 'else'部分はStringキーのシリアル化中に例外になります:'原因:: com.fasterxml.jackson.core.JsonGenerationException:文字列を書き込めません。フィールド名(context:Object)を期待しています。 'serializers.defaultSerializeValue(value、gen)'と 'gen.writeString(value.toString())'を試しましたが、同じエラーが発生しました。 – Rodion

関連する問題