2017-09-19 2 views
2

Map<String, Object>의 형식으로 DB에서 결과를 얻었습니다.이 결과는 REST-service에서 json으로 반환해야합니다. 지도의 값은 PGObject, String, IntegerDate을 비롯한 다양한 유형이 될 수 있습니다.Map <String, Object>에 Jackson 사용자 정의 값 직렬 변환기를 사용하는 방법?

List<?>에서 제대로 작동하지만 "Map<String, Object>"에서는 작동하지 않는 "jsonb"유형의 org.postgresql.util.PGObject 클래스에 대한 사용자 지정 serializer를 작성했습니다.

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에 대한 serializer를 추가 할 수 있습니다.

다음 serializer 자체에서 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

이 해결 방법을 사용하려면 다른 모든 클래스 형식의 serialization을 다른 "기본"또는 "일반"serializer에 위임해야합니다. 나는 그런 것을 찾지 못했다. – Rodion

+0

obejct 매퍼를 사용할 수 있습니다. 내 업데이트 된 PgObjectSerializer를 참조하십시오. –

+0

불행히도 'else'부분은 String 키 직렬화 중에 예외가 발생합니다.'Caused by : com.fasterxml.jackson.core.JsonGenerationException : 문자열을 쓸 수 없습니다. 예상 필드 이름 (context : Object)'. 'serializers.defaultSerializeValue (value, gen)'및'gen.writeString (value.toString()) '을 시도했지만 동일한 오류가 발생했습니다. – Rodion