Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在jackson库中区分空值字段和缺少字段_Java_Json_Xml_Jackson - Fatal编程技术网

Java 如何在jackson库中区分空值字段和缺少字段

Java 如何在jackson库中区分空值字段和缺少字段,java,json,xml,jackson,Java,Json,Xml,Jackson,我们正在使用一个API,该API提供xml字段。我们必须为消费者将xml转换为json。我们需要以XML的形式显示我们得到的内容,并且只显示那些字段 如果字段存在且存在值,则显示它 如果字段不存在,则不显示它 如果字段存在且为空/无值,则按原样显示该字段 我看到的是一般注释 @JsonInclude(非空)可用于排除空值。我无法使用此选项,因为我仍希望在json中看到空值字段 @JsonInclude(非不存在)可用于排除空值和“不存在”的值。我无法使用此选项,因为我仍然希望看到json中的空字

我们正在使用一个API,该API提供xml字段。我们必须为消费者将xml转换为json。我们需要以XML的形式显示我们得到的内容,并且只显示那些字段

  • 如果字段存在且存在值,则显示它
  • 如果字段不存在,则不显示它
  • 如果字段存在且为空/无值,则按原样显示该字段 我看到的是一般注释

    @JsonInclude(非空)
    可用于排除空值。我无法使用此选项,因为我仍希望在json中看到空值字段

    @JsonInclude(非不存在)
    可用于排除空值和“不存在”的值。我无法使用此选项,因为我仍然希望看到json中的空字段和空字段。与
    JsonInclude相同(非空)


    所以我的问题是,如果我不指定这些属性中的任何一个,我能实现我想要的吗?换句话说,如果我没有指定其中任何一个,那么jackson的行为就是显示所有在dynamic sense上有空值的字段?我主要关心的是这里的动态响应。对于每个请求,字段可能存在或不存在。我们必须在json中显示我们在XML中接收到的确切内容

    如果您想区分
    null
    值字段和不存在的字段,最通用的方法是使用
    Map
    JsonNode
    而不是
    POJO
    POJO
    类具有常量结构,
    Map
    JsonNode
    具有动态-仅包含实际放在那里的内容。让我们创建一个简单的应用程序,从文件中读取
    XML
    有效负载,并创建
    JSON
    响应:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.dataformat.xml.XmlMapper;
    
    import java.io.File;
    import java.util.Map;
    
    public class JsonApp {
    
        public static void main(String[] args) throws Exception {
            File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
    
            XmlMapper xmlMapper = new XmlMapper();
            Map map = xmlMapper.readValue(xmlFile, Map.class);
    
            ObjectMapper jsonMapper = new ObjectMapper();
            String json = jsonMapper.writeValueAsString(map);
    
            System.out.println(json);
        }
    }
    
    现在来看一些示例,其中我们测试将为
    empty
    null
    和缺少的节点生成什么
    JSON

    测试0-0 输入
    XML

    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <a>A</a>
        <c>
            <c1>Rick</c1>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <b>1</b>
        <c>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    测试0-1 输入
    XML

    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <a>A</a>
        <c>
            <c1>Rick</c1>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <b>1</b>
        <c>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    测试0-2 输入
    XML

    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <a>A</a>
        <c>
            <c1>Rick</c1>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <b>1</b>
        <c>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    这种简单而快速的解决方案的最大问题是我们丢失了原语的类型信息。例如,如果
    b
    Integer
    ,我们应该在
    JSON
    中返回它作为没有引号的数字原语:
    字符。要解决这个问题,我们应该使用
    POJO
    模型,它允许我们找到所有必需的类型。让我们为我们的示例创建
    POJO
    模型:

    @JsonFilter("allowedFields")
    class Root {
        private String a;
        private Integer b;
        private C c;
    
        // getters, setters
    }
    
    @JsonFilter("allowedFields")
    class C {
        private String c1;
        private Integer c2;
    
        // getters, setters
    }
    
    我们需要将简单的
    XML->Map->JSON
    算法更改为以下算法:

  • 将JSON读为
    Map
    JsonNode
  • 查找所有字段名
  • 使用找到的名称创建
    FilterProvider
    ——请注意,过滤器注册到
    allowedFields
    name,与
    @JsonFilter
    注释中使用的相同
  • Map
    转换为
    POJO
    进行类型强制
  • 使用过滤器写入
    POJO
  • 简单的应用程序可能如下所示:

    import com.fasterxml.jackson.annotation.JsonFilter;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ArrayNode;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
    import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
    import com.fasterxml.jackson.dataformat.xml.XmlMapper;
    
    import java.io.File;
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.Set;
    
    public class JsonApp {
    
        public static void main(String[] args) throws Exception {
            File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
    
            NodesWalker walker = new NodesWalker();
    
            XmlMapper xmlMapper = new XmlMapper();
            JsonNode root = xmlMapper.readValue(xmlFile, JsonNode.class);
            Set<String> names = walker.findAllNames(root);
    
            SimpleFilterProvider filterProvider = new SimpleFilterProvider();
            filterProvider.addFilter("allowedFields", SimpleBeanPropertyFilter.filterOutAllExcept(names));
    
            ObjectMapper jsonMapper = new ObjectMapper();
            jsonMapper.setFilterProvider(filterProvider);
    
            Root rootConverted = jsonMapper.convertValue(root, Root.class);
            String json = jsonMapper.writeValueAsString(rootConverted);
    
            System.out.println(json);
        }
    }
    
    class NodesWalker {
    
        public Set<String> findAllNames(JsonNode node) {
            Set<String> names = new HashSet<>();
    
            LinkedList<JsonNode> nodes = new LinkedList<>();
            nodes.add(node);
            while (nodes.size() > 0) {
                JsonNode first = nodes.removeFirst();
                if (first.isObject()) {
                    ObjectNode objectNode = (ObjectNode) first;
                    objectNode.fields().forEachRemaining(e -> {
                        names.add(e.getKey());
                        JsonNode value = e.getValue();
                        if (value.isObject() || value.isArray()) {
                            nodes.add(value);
                        }
                    });
                } else if (first.isArray()) {
                    ArrayNode arrayNode = (ArrayNode) first;
                    arrayNode.elements().forEachRemaining(e -> {
                        if (e.isObject() || e.isArray()) {
                            nodes.add(e);
                        }
                    });
                }
            }
    
            return names;
        }
    }
    
    输出
    JSON

    {"a":"A","c":{"c1":"Rick","c2":null}}
    
    {"c":null}
    
    {"a":"A","b":1,"c":{"c1":"Rick","c2":58}}
    
    {"b":1,"c":{"c2":null}}
    
    {"c":null}
    
    测试1-1 输入
    XML

    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <a>A</a>
        <c>
            <c1>Rick</c1>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <b>1</b>
        <c>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    测试1-2 输入
    XML

    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <a>A</a>
        <c>
            <c1>Rick</c1>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    <Root>
        <a>A</a>
        <b>1</b>
        <c>
            <c1>Rick</c1>
            <c2>58</c2>
        </c>
    </Root>
    
    <Root>
        <b>1</b>
        <c>
            <c2/>
        </c>
    </Root>
    
    <Root>
        <c/>
    </Root>
    
    在所有这些测试之后,我们发现动态检查字段是否为
    null
    为空
    不存在
    并不是一项容易的任务。即使如此,上述两种解决方案对简单模型都有效,您应该测试它们以获得所有想要生成的响应。当模型复杂且包含许多复杂注释时,例如:
    @JsonTypeInfo
    @JsonSubTypes
    Jackson
    侧或
    @xmlementwrapper
    @xmlanyement
    JAXB
    侧,这使得这项任务很难实现

    我认为在您的示例中,最好的解决方案是使用
    @JsonInclude(非空)
    XML
    端的所有设置字段发送给客户端。
    null
    缺席
    应在客户端得到相同的处理。业务逻辑不应依赖于
    JSON
    有效负载中设置为
    null
    缺席
    的事实字段

    另见:


    非常感谢您提供的详细信息。我同意业务逻辑不应该依赖于显示空字段。这比业务逻辑更符合法律和法规。@Ags,我理解这些论点。我想,我展示了fluffy如何将
    XML
    转换为
    JSON
    ,这不是一项容易的任务。我们应该深入理解
    XML
    中的
    empty
    节点和
    JSON
    中的
    empty
    节点的含义。您可以创建一些规则,在
    X
    Y
    Z
    情况下如何处理,并尝试创建自定义解决方案。