Jackson中的ValueNode
的所有子类(JSON库)具有获取基础值对象的不同方法,例如: IntNode
有getIntValue
,BooleanNode
有getBooleanValue
,依此类推。
为什么没有简称为getValue
的通用/多态方法只返回Object
,Object
为Integer
或Boolean
等等。,根据调用该方法的节点类型?
或者......实际上有这样的方法吗? 我需要这样的方法用于我的目的但似乎图书馆设计师没有发现添加这样的方法会有用。或者......出于某种原因,该方法是否故意丢失?
我的目的:在下面的代码中,我遍历树并生成仅由HashMap
,Object[]
和Java基本类型组成的结构(如Integer
,Boolean
等)。如果我有这样的方法,而不是所有这些 if-else if-else if 阻止,我只需要一个方法调用(在{{ 1}}是叶节点,即JsonNode
的子类型。但似乎我在杰克逊身上没有这样的方法。因此,我必须编写所有那些丑陋的 if-else if-else if 块。
CODE:
ValueNode
答案 0 :(得分:4)
由于您要返回Object
,因此可以使用此类
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(nd,Object.class);
对于这个特定的测试用例,它起作用
JsonNode nodeBool = BooleanNode.TRUE;
Object objectBool = mapper.convertValue(nodeBool,Object.class);
Boolean returnValBool = (Boolean) objectBool;
System.err.println(returnValBool);
JsonNode nodeDouble = new DoubleNode(3.4);
Object objectDouble = mapper.convertValue(nodeDouble,Object.class);
Double returnValDouble = (Double) objectDouble;
System.err.println(returnValDouble);
并且按预期结束了:
true
3.4
答案 1 :(得分:2)
这是一个有趣的问题:)
我不确定为什么没有通用方法。我相信这可能与他们不仅处理对象类型的事实有关吗?好吧,我没有资格证明他们的设计决定是合理的,但是我可以用你的通用方法来帮助你。
你是对的,你不能只调用value(),但你只能调用serialize(..,..)
更多细节:
所有值节点都拥有自己的值。所有值节点都知道如何序列化。我们可以利用这一点。
注意:这会有点hacky
您可以编写自己的序列化程序并让它存储您的值以检索它们:
public static class MyGen extends GeneratorBase {
protected MyGen(int features, ObjectCodec codec) {
super(features, codec);
}
private Object currentObject = null;
@Override
public void flush() throws IOException {
// do nothing
}
@Override
protected void _releaseBuffers() {
// do nothing
}
@Override
protected void _verifyValueWrite(String typeMsg) throws IOException {
// do nothing
}
@Override
public void writeStartArray() throws IOException {
// do nothing
}
@Override
public void writeEndArray() throws IOException {
} // do nothing
@Override
public void writeStartObject() throws IOException {
// do nothing
}
@Override
public void writeEndObject() throws IOException {
// do nothing
}
@Override
public void writeFieldName(String name) throws IOException {
// do nothing
}
@Override
public void writeString(String text) throws IOException {
currentObject = text;
}
@Override
public void writeString(char[] text, int offset, int len) throws IOException {
currentObject = new String(text);
}
@Override
public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException {
currentObject = new String(text);
}
@Override
public void writeUTF8String(byte[] text, int offset, int length) throws IOException {
currentObject = new String(text);
}
@Override
public void writeRaw(String text) throws IOException {
currentObject = new String(text);
}
@Override
public void writeRaw(String text, int offset, int len) throws IOException {
currentObject = new String(text);
}
@Override
public void writeRaw(char[] text, int offset, int len) throws IOException {
currentObject = new String(text);
}
@Override
public void writeRaw(char c) throws IOException {
currentObject = new Character(c);
}
@Override
public void writeBinary(Base64Variant bv, byte[] data, int offset, int len) throws IOException {
currentObject = bv;
}
@Override
public void writeNumber(int v) throws IOException {
currentObject = new Integer(v);
}
@Override
public void writeNumber(long v) throws IOException {
currentObject = new Long(v);
}
@Override
public void writeNumber(BigInteger v) throws IOException {
currentObject = v;
}
@Override
public void writeNumber(double v) throws IOException {
currentObject = new Double(v);
}
@Override
public void writeNumber(float v) throws IOException {
currentObject = new Float(v);
}
@Override
public void writeNumber(BigDecimal v) throws IOException {
currentObject = v;
}
@Override
public void writeNumber(String encodedValue) throws IOException {
currentObject = encodedValue;
}
@Override
public void writeBoolean(boolean state) throws IOException {
currentObject = new Boolean(state);
}
@Override
public void writeNull() throws IOException {
currentObject = null;
}
}
请注意,这是一个简单有趣的原型测试,可能需要更多考虑。
但有了这个,我可以做到:
public static void main(String[] args) throws JsonProcessingException, IOException {
MyGen gen = new MyGen(0, new ObjectMapper());
String test = "{ \"a\" : \"test\", \"b\" : 1, \"c\" : true, \"d\" : 2.5 }";
JsonNode tree = new ObjectMapper().readTree(test);
Impl instance = new DefaultSerializerProvider.Impl();
ObjectMapper m = new ObjectMapper();
for(JsonNode node : tree) {
node.serialize(gen, instance);
Object currentObject = gen.currentObject;
System.out.println(currentObject);
}
}
打印哪些:
test
1
true
2.5
希望有帮助:)
阿图尔
Ps:另一个答案更短更好 - 但我认为这也很酷,所以无论如何我都会发布它
编辑:
关于你的一条评论。生成器将检索原始值,由您来保留该值。你将完全控制它。
答案 2 :(得分:0)
为解决此问题,我扩展了StdDeseralizer
并创建了EnhancedDeserializer。
在反序列化过程中,调用deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
时,我只存储了objectMapper = (ObjectMapper) jsonParser.getCodec()
。因为它实际上是ObjectMapper
实例。
之后,我就可以打电话给objectMapper.convertValueMethod
了。
public abstract class EnhancedDeserializer<T> extends StdDeserializer<T> {
protected ObjectMapper objectMapper;
public EnhancedDeserializer(final Class<?> clazz) {
super(clazz);
}
@Override
public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
objectMapper = (ObjectMapper) jsonParser.getCodec(); // trick! the codec is the ObjectMapper
return deserialize(objectMapper.readTree(jsonParser));
}
public abstract T deserialize(JsonNode node);
public <E> E readAs(JsonNode node, Class<E> clazz) {
if (node == null) {
return null;
}
return objectMapper.convertValue(node, clazz);
}
public <E> E readAs(JsonNode node, String key, Class<E> clazz) {
if (node == null) {
return null;
}
return readAs(node.get(key), clazz);
}
public <E> E readAs(JsonNode node, TypeReference<E> typeReference) {
if (node == null) {
return null;
}
return objectMapper.convertValue(node, typeReference);
}
public <E> E readAs(JsonNode node, String key, TypeReference<E> typeReference) {
if (node == null) {
return null;
}
return readAs(node.get(key), typeReference);
}
}
为了证明我有一个简单的对象。
public class MyObject {
private Object fieldObject;
private Long fieldLong;
private String fieldString;
private Map<String, Object> fieldWithGeneric;
// getters setters omitted
}
使用EnhancedDeserializer
进行反序列化的代码非常简单:
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.Map;
public class MyObjectDeserializer extends EnhancedDeserializer<MyObject> {
public MyObjectDeserializer() {
super(MyObject.class);
}
@Override
public MyObject deserialize(JsonNode node) {
MyObject myObject = new MyObject();
myObject.setFieldObject(readAs(node, "obj", Object.class));
myObject.setFieldLong(readAs(node, "lng", Long.class));
myObject.setFieldString(readAs(node, "str", String.class));
myObject.setFieldWithGeneric(readAs(node, "map", new TypeReference<Map<String, Object>>() {
}));
return myObject;
}
}
最后是测试:
public class MyObjectDeserializerTest {
private ObjectMapper objectMapper;
@Before
public void setup() {
objectMapper = new ObjectMapper()
.registerModule(new SimpleModule()
.addDeserializer(MyObject.class, new MyObjectDeserializer()));
}
@Test
public void deserialize_ObjectField_Integer() throws IOException {
final MyObject myObject = objectMapper.readValue(aSimpleJsonField("obj", "1"), MyObject.class);
assertThat(myObject.getFieldObject(), is(1));
}
@Test
public void deserialize_ObjectField_String() throws IOException {
final MyObject myObject = objectMapper.readValue(aSimpleJsonField("obj", "\"my-string\""), MyObject.class);
assertThat(myObject.getFieldObject(), is("my-string"));
}
@Test
public void deserialize_ObjectField_Double() throws IOException {
final MyObject myObject = objectMapper.readValue(aSimpleJsonField("obj", "123.456"), MyObject.class);
assertThat(myObject.getFieldObject(), is(123.456));
}
@Test
public void deserialize_LongField() throws IOException {
final MyObject myObject = objectMapper.readValue(aSimpleJsonField("lng", "456789123456789"), MyObject.class);
assertThat(myObject.getFieldLong(), is(456789123456789L));
}
@Test
public void deserialize_StringField() throws IOException {
final MyObject myObject = objectMapper.readValue(aSimpleJsonField("str", "\"hello world\""), MyObject.class);
assertThat(myObject.getFieldString(), is("hello world"));
}
@Test
public void deserialize_genericField() throws IOException {
final ObjectNode root = objectMapper.createObjectNode();
final ObjectNode genericNode = objectMapper.createObjectNode();
genericNode.put("str_0", "string");
genericNode.put("int_1", 123);
genericNode.put("long_2", 123456789123456L);
genericNode.put("double_3", 987.654);
genericNode.put("bool_4", true);
root.set("map", genericNode);
final MyObject myObject = objectMapper.readValue(objectMapper.writeValueAsString(root), MyObject.class);
final Map<String, Object> map = myObject.getFieldWithGeneric();
assertThat(map, notNullValue());
assertThat(map.get("str_0"), is("string"));
assertThat(map.get("int_1"), is(123));
assertThat(map.get("long_2"), is(123456789123456L));
assertThat(map.get("double_3"), is(987.654));
assertThat(map.get("bool_4"), is(true));
}
private String aSimpleJsonField(String key, String value) {
return "{ \"" + key + "\" : " + value + " }";
}
}
通过放置EnhancedDeserializer
,您的代码将非常简单,并且更重要的是类型安全的。现在,您可以删除raw
unchecked
抑制。
希望对您有帮助。