Java 防止Jackson ObjectMapper自动转换字符串()-格式化复合映射键
我正在使用Java 防止Jackson ObjectMapper自动转换字符串()-格式化复合映射键,java,json,jackson,tostring,Java,Json,Jackson,Tostring,我正在使用com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString()从JavaPOJO生成JSON 我的一个对象(我们称之为ResultSheet)包含一个属性映射结果ResultId表示一个复合主键(由两个FK组成) 在遇到ResultId时,ObjectMapper似乎意识到这不能直接用JSON表示,因为JSON映射键必须是字符串。因此,它将输出ResultId的toString()。(在这种特殊情况下,这会生成一个格式为
com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString()
从JavaPOJO生成JSON
我的一个对象(我们称之为ResultSheet
)包含一个属性映射结果
ResultId
表示一个复合主键(由两个FK组成)
在遇到ResultId
时,ObjectMapper
似乎意识到这不能直接用JSON表示,因为JSON映射键必须是字符串。因此,它将输出ResultId
的toString()
。(在这种特殊情况下,这会生成一个格式为“42:43”
的字符串,但这只是因为toString()
当前正是这样实现的。)
我怎样才能阻止它这样做?当前行为隐藏了这样一个事实,即被封送的结构不能正确地表示为JSON结构。它还将当前的toString()
实现泄漏到我的web服务的API中
我宁愿抛出一个异常,告诉我何时用作映射键的值不是字符串
——或者至少,何时转换为字符串
。(例如,我不太担心Long
键是toString()
-ed。)
我已经研究了序列化功能
设置,但它们似乎都没有解决这个问题
有没有办法防止这种情况?是否可以以一般方式进行,即不只是针对该特定类,而是在将来可能出现这种情况的任何情况下,添加新类(其中一些可能用作映射键)时
注意,在这种情况下,使
toString()
抛出异常将不是一种可接受的黑客行为。要解决此问题,您可以实现并注册自己的com.fasterxml.jackson.databind.ser.BeanSerializerModifier
类。和重写方法。实现总是可以返回引发异常的序列化器。请参见以下示例:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
public class JsonKeySerializerApp {
public static void main(String[] args) throws IOException {
SimpleModule keyExceptionSerializerModule = new SimpleModule();
keyExceptionSerializerModule.setSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifyKeySerializer(SerializationConfig config, JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
// specify classes you want to allow to be serialized as keys
if (valueType.getRawClass().getPackage().getName().startsWith("java.")) {
return serializer;
}
return new JsonSerializer<Object>() {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) {
throw new UnsupportedOperationException("You can not serialize POJO as keys!");
}
};
}
});
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(keyExceptionSerializerModule);
Map<ResultId, Long> map = Collections.singletonMap(new ResultId(1, 2), 1L);
mapper.writeValue(System.out, map);
}
}
@AllArgsConstructor
@Data
class ResultId {
private int id1;
private int id2;
}
所以您希望
映射
不序列化为{“”:,…}
,而是序列化为[{“键”:,“值”:},…]
?与将Map
转换为带有Map.Entry
作为名称/值对的JSON对象不同,您基本上希望将映射转换为列表
?否。如果键不是字符串,我希望它完全失败。我不希望它只是假设它可以toString()
映射中的(非字符串)键,然后继续执行,这看起来很有希望。谢谢
{Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: You can not serialize POJO as keys! (through reference chain: java.util.Collections$SingletonMap["ResultId(id1=1, id2=2)"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:725)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:643)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33)