首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Jackson -泛型getValue方法

Jackson -泛型getValue方法
EN

Stack Overflow用户
提问于 2016-09-15 22:47:29
回答 3查看 1.9K关注 0票数 6

JSON (JSON库)中ValueNode的所有子类都有不同的方法来获取底层的值对象,例如IntNodegetIntValueBooleanNodegetBooleanValue等等。

为什么没有名为getValue的泛型/多态方法,它只返回一个Object,并且该ObjectIntegerBoolean等,这取决于调用该方法的节点的类型。

或者..。究竟有没有这样的方法呢?我需要这样的方法来达到我的目的,但是似乎库设计者并没有发现添加这样的方法会有什么用处。或者..。该方法是出于某种原因故意遗漏的吗?

我的目的:在下面的代码中,我遍历树并生成一个只由HashMapObject[]和Java基本类型(如IntegerBoolean等)组成的结构。如果我有这样一个方法,而不是所有这些 If -else if-else if块,我将只有一个方法调用(在JsonNode是叶节点的情况下,即ValueNode的子类型)。但我在杰克逊身上似乎没有这样的方法。所以我不得不编写所有这些丑陋的if-else if-else if块。

代码:

代码语言:javascript
复制
    @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() + " |||");
        }
EN

回答 3

Stack Overflow用户

发布于 2016-09-15 23:20:32

由于您返回的是Object,因此可以使用如下代码

代码语言:javascript
复制
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(nd,Object.class);

对于这个特定的测试用例,它是有效的

代码语言:javascript
复制
        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);

它的输出结果与预期一致:

代码语言:javascript
复制
true
3.4
票数 5
EN

Stack Overflow用户

发布于 2016-09-15 23:23:45

这是一个有趣的问题:)

我不确定为什么没有泛型方法。我相信这可能与他们不仅处理对象类型的事实有关。好吧,我真的没有资格证明他们的设计决定是合理的,但是我可以用你的泛型方法来帮助你。

您说得对,您不能只调用value(),而可以只调用serialize(..,..)

更多详细信息:

所有值节点都有自己的值。所有值节点都知道如何序列化。我们可以利用这一点。

备注:这将是一个稍显老套的

您可以编写自己的序列化程序,并让它存储您的值以检索它们:

代码语言:javascript
复制
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;
        }

    }

请注意,这只是一个有趣的原型测试,可能需要多加考虑。

但是有了这个,我可以做:

代码语言:javascript
复制
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);
        }

    }

打印的内容:

代码语言:javascript
复制
test
1
true
2.5

希望这能有所帮助:)

文章

Ps:另一个答案要短得多,也更好--但我觉得这也很酷,所以我还是要把它贴出来

编辑:

关于你的一条评论。生成器将检索原始值,并由您保留该值。你将会完全控制它。

票数 2
EN

Stack Overflow用户

发布于 2018-07-21 03:22:02

为了解决这个问题,我扩展了StdDeseralizer并创建了一个EnhancedDeserializer。在调用deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)的反序列化过程中,我只是存储objectMapper = (ObjectMapper) jsonParser.getCodec()。因为它实际上是ObjectMapper实例。在此之后,我可以调用执行此工作的objectMapper.convertValueMethod

代码语言:javascript
复制
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);
}

}

来证明我有一个简单的物体。

代码语言:javascript
复制
public class MyObject {

    private Object fieldObject;

    private Long fieldLong;

    private String fieldString;

    private Map<String, Object> fieldWithGeneric;

    // getters setters omitted
}

使用EnhancedDeserializer实现的反序列化代码非常简单:

代码语言:javascript
复制
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;
    }
}

最后是测试:

代码语言:javascript
复制
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抑制。

我希望它能帮上忙。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39514106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档