JSON (JSON库)中ValueNode
的所有子类都有不同的方法来获取底层的值对象,例如IntNode
有getIntValue
,BooleanNode
有getBooleanValue
等等。
为什么没有名为getValue
的泛型/多态方法,它只返回一个Object
,并且该Object
是Integer
或Boolean
等,这取决于调用该方法的节点的类型。
或者..。究竟有没有这样的方法呢?我需要这样的方法来达到我的目的,但是似乎库设计者并没有发现添加这样的方法会有什么用处。或者..。该方法是出于某种原因故意遗漏的吗?
我的目的:在下面的代码中,我遍历树并生成一个只由HashMap
、Object[]
和Java基本类型(如Integer
、Boolean
等)组成的结构。如果我有这样一个方法,而不是所有这些 If -else if-else if块,我将只有一个方法调用(在JsonNode
是叶节点的情况下,即ValueNode
的子类型)。但我在杰克逊身上似乎没有这样的方法。所以我不得不编写所有这些丑陋的if-else if-else if块。
代码:
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object traverse(JsonNode nd) {
if (nd instanceof ObjectNode) {
ObjectNode ndd = (ObjectNode) nd;
HashMap mp = new HashMap();
Iterator<String> it = ndd.getFieldNames();
while (it.hasNext()) {
String s = it.next();
mp.put(s, traverse(ndd.get(s)));
}
return mp;
} else if (nd instanceof ArrayNode) {
ArrayNode ndd = (ArrayNode) nd;
Object[] arr = new Object[ndd.size()];
for (int i = 0; i < ndd.size(); i++) {
arr[i] = traverse(ndd.get(i));
}
return arr;
} else if (nd instanceof NullNode) {
// NullNode ndd = (NullNode)nd;
return null;
} else if (nd instanceof BooleanNode) {
BooleanNode ndd = (BooleanNode) nd;
return ndd.getBooleanValue();
} else if (nd instanceof IntNode) {
IntNode ndd = (IntNode) nd;
return ndd.getIntValue();
} else if (nd instanceof LongNode) {
LongNode ndd = (LongNode) nd;
return ndd.getLongValue();
} else if (nd instanceof DoubleNode) {
DoubleNode ndd = (DoubleNode) nd;
return ndd.getDoubleValue();
} else if (nd instanceof DecimalNode) {
DecimalNode ndd = (DecimalNode) nd;
return ndd.getDecimalValue();
} else if (nd instanceof BigIntegerNode) {
BigIntegerNode ndd = (BigIntegerNode) nd;
return ndd.getBigIntegerValue();
} else if (nd instanceof TextNode) {
TextNode ndd = (TextNode) nd;
return ndd.getTextValue();
}
throw new IllegalStateException("Failed while traversing the JSON tree at node: ||| " + nd.asText() + " |||");
}
发布于 2016-09-15 23:20:32
由于您返回的是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
发布于 2016-09-15 23:23:45
这是一个有趣的问题:)
我不确定为什么没有泛型方法。我相信这可能与他们不仅处理对象类型的事实有关。好吧,我真的没有资格证明他们的设计决定是合理的,但是我可以用你的泛型方法来帮助你。
您说得对,您不能只调用value(),而可以只调用serialize(..,..)
更多详细信息:
所有值节点都有自己的值。所有值节点都知道如何序列化。我们可以利用这一点。
备注:这将是一个稍显老套的
您可以编写自己的序列化程序,并让它存储您的值以检索它们:
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:另一个答案要短得多,也更好--但我觉得这也很酷,所以我还是要把它贴出来
编辑:
关于你的一条评论。生成器将检索原始值,并由您保留该值。你将会完全控制它。
发布于 2018-07-21 03:22:02
为了解决这个问题,我扩展了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
抑制。
我希望它能帮上忙。
https://stackoverflow.com/questions/39514106
复制相似问题