如何使用Java Objects表示以下json模式?

时间:2022-06-24 19:33:47

I have the below Json Schema.

我有下面的Json Schema。

 {  
       "name":{  
          "first":{  
         "attributeValue":"firstName",
         "attributeType":1,
         "dataType":1
          },
          "last":{  
         "attributeValue":"lastName",
         "attributeType":1,
         "dataType":1
          }
       },
       "age":{  
          "attributeValue":"age",
          "attributeType":1,
          "dataType":2
       },
       "address":{  
          "number":{  
         "attributeValue":"number",
         "attributeType":1,
         "dataType":1
          },
          "street":{  
         "attributeValue":"street",
         "attributeType":1,
         "dataType":1
          },
          "city":{  
         "attributeValue":"city",
         "attributeType":1,
         "dataType":1
          },
          "country":{  
         "attributeValue":"country",
         "attributeType":1,
         "dataType":1
          }
       },
       "fullName":{  
          "attributeValue":"#firstName.concat(' ').concat(#lastName)",
          "attributeType":2,
          "dataType":1
       }
    }

In here, each node that has attributeValue,dataType and attributeType nodes are called "Field". Every other parent node is a handler. "name" is a handler which has "first" and "last" fields. But for age, since there is no parent key, there should be a handler created named "age" and a field "age" should be added to that. Handlers can have handlers. Handlers have fields in them. Below is the Handler object representation.

在这里,具有attributeValue,dataType和attributeType节点的每个节点都称为“Field”。每个其他父节点都是一个处理程序。 “name”是具有“first”和“last”字段的处理程序。但是对于年龄,由于没有父键,因此应该创建一个名为“age”的处理程序,并且应该添加一个字段“age”。处理程序可以有处理程序。处理程序中包含字段。下面是Handler对象表示。

  public interface Handler<T> {
     void addField(Field field);
     void addHandler(Handler handler);
     String getName();
     List<Field> getFields();
     T handle(T target);
 }

Below is the field representation.

以下是字段表示。

 public interface Field<T> {
     void setValue(String value);
     T getField();
     String getFieldName();
 }

Now I need to parse the json schema and return a list of handlers. Below is what I tried.

现在我需要解析json模式并返回一个处理程序列表。以下是我的尝试。

 private List<Handler> parseJsonSchema(Handler handler, String jsonSchema) throws JSONMapperException {
        List<Handler> handlerList = new ArrayList<>();
        boolean isParentLeaf = false;
        Field<ObjectNode> objectNodeField = null;
        try {
            JsonNode rootNode = objectMapper.readTree(jsonSchema);
            Iterator<Map.Entry<String, JsonNode>> childrenIterator = rootNode.fields();
            while (childrenIterator.hasNext()) {
            Map.Entry<String, JsonNode> field = childrenIterator.next();
            System.out.println("Key: " + field.getKey() + "\tValue:" + field.getValue());
            if (field.getValue().has("attributeValue") && field.getValue().has("attributeType")
                    && field.getValue().has("dataType")) {
                if (handler == null) {
                    handler = jsonNodeHandlerFactory.create(field.getKey());
                    isParentLeaf = true;
                }
                JsonNode valueNode = field.getValue();
                //String fieldName = valueNode.get("attributeValue").toString();
                String fieldName = field.getKey();
                String dataType = valueNode.get("dataType").toString();
                switch (dataType) {
                    case "1":
                        objectNodeField = dataFieldFactory.createStringField(fieldName);
                        break;
                    case "2":
                        objectNodeField = dataFieldFactory.createIntField(fieldName);
                        break;
                    case "3":
                        objectNodeField = dataFieldFactory.createBooleanField(fieldName);
                        break;
                    default:
                        break;
                }
                handler.addField(objectNodeField);
                if(isParentLeaf) {
                    handlerList.add(handler);
                    handler =null;
                }
            } else {
                handler = jsonNodeHandlerFactory.create(field.getKey());
                List<Handler> handlers = parseJsonSchema(handler, field.getValue().toString());
                for (Handler handler1 : handlers) {
                    if(handler != null) { //means we already have a handler and we've come into another handler
                        handler.addHandler(handler1);
                        handlerList.add(handler);
                    } else {
                        handlerList.add(handler1);
                    }
                }
                handler = null;
            }
            if ((handler != null && handler.getFields().size() == rootNode.size())) {
                handlerList.add(handler);
            }
            }
        } catch (IOException e) {
            logger.error(JSON_SCHEMA_PARSE_EXCEPTION, e);
            throw new JSONMapperException(JSON_SCHEMA_PARSE_EXCEPTION);
        }
        return handlerList;
        }

But it overrides handlers, when there are handlers within handlers. Also it looks pretty clumsy with too many null assignments and if checks. Is there a better way to do what this method is already doing? That is return the schema as a list of handlers. Any help would be much appreciated.

但是当处理程序中有处理程序时,它会覆盖处理程序。它也看起来非常笨拙,有太多的空分配和检查。有没有更好的方法来做这个方法已经做的事情?这将返回架构作为处理程序列表。任何帮助将非常感激。

1 个解决方案

#1


1  

First of all, it seems to me that a better place for this question would be the Code Review forum.

首先,在我看来,这个问题的一个更好的地方是代码审查论坛。

However, to get you started, I have few tips:

但是,为了帮助您入门,我提供了一些提示:

  1. As your intuition told you, the code indeed looks "clumsy" or, in other words, not implementing OO principles (or even just plain SW development ones) to good extent.

    正如你的直觉告诉你的那样,代码确实看起来“笨拙”,换句话说,在很大程度上没有实现OO原则(甚至只是简单的SW开发原则)。

  2. I would start by looking at the long branches of the if statememnt, making each branch into separate methods. something like parseField() and parseHandler() and perhaps there are other such blocks of code that can be isolated into separate methods. This will make the parseJsonSchema() method much more readable and debugable (this is, for instance, just plain SW development principle)

    我将首先查看if statememnt的长分支,使每个分支成为单独的方法。像parseField()和parseHandler()这样的东西,也许还有其他这样的代码块可以被分离成单独的方法。这将使parseJsonSchema()方法更具可读性和可调试性(例如,这只是简单的SW开发原理)

  3. The abovementioned principle is aplicable not only in cases of long code blocks, but also in short ones that can be isolated and hide details for the sake of clarity: the if condition that determines if field is Field or Handler. Make it into isField(Map.Entry<String, JsonNode> entry) method. and perhaps you see now why naming it field is not the best option if it can be either Field or Handler. Same comment goes for the handler1 variable. It must have a better more comprehensible name.

    上述原理不仅适用于长代码块的情况,而且适用于可以隔离的短代码并且为了清楚起见隐藏细节:确定字段是字段还是处理程序的if条件。使其成为isField(Map.Entry entry)方法。也许你现在看到为什么命名它字段不是最好的选择,如果它可以是Field或Handler。对handler1变量也有相同的注释。它必须有一个更易于理解的名称。 ,jsonnode>

  4. It is nice that you're using a factory to instantiate Fields. However, other then calling the constructor for a concreate Field implementation, I fail to see what else is your factory doing, because all the parsing of the json and the decision making is done in the parseJsonSchema(). as a rule of thumb, the factory should have one method for each returned type (without generics). So, your factory is returning various Fields, then it should have just createField() that gets a JsonNode and parses what it needs to decide on which implementation to instantiate.

    很高兴您使用工厂来实例化Fields。然而,除了然后调用构造函数进行concreate Field实现之外,我没有看到你的工厂还在做什么,因为json的所有解析和决策都是在parseJsonSchema()中完成的。根据经验,工厂应该为每种返回类型都有一个方法(没有泛型)。因此,您的工厂正在返回各种字段,然后它应该只有createField()获取JsonNode并解析它需要决定实例化哪个实现。

  5. Another OO principle to follow: declare your variable in the inner-most scope that you can. objectNodeField is only accessed inside the branch that handles fields, so put the declaration inside the curly brackets of this branch. do not declare it in the scope of the whole parseJsonSchema(). This makes it easier to understand the scope of the variable and avoid erroneous access outside of the applicable scope.

    要遵循的另一个OO原则:在最内部的范围内声明您的变量。 objectNodeField只能在处理字段的分支内访问,因此请将声明放在此分支的大括号内。不要在整个parseJsonSchema()的范围内声明它。这使得更容易理解变量的范围并避免在适用范围之外的错误访问。

    Now, if you make the the branch into parseField() method, the objectNodeField variable becomes local to that new method. See how it makes the code better in terms of clarity and stability?

    现在,如果将分支设置为parseField()方法,则objectNodeField变量将成为该新方法的本地变量。了解它如何使代码在清晰度和稳定性方面更好?

  6. While we are looking at this variable, I am thinking why did you make its generic type ObjectNode, when its concrete variances are String, Integer and Boolean? how can StringField implement handle() method of Field interface and actually handle ObjectNode ? IMO, objectNodeField should be declared Field<Object> or better yet, Field<?> so it can host the abovementioned types.

    当我们查看这个变量时,我在想为什么你的泛型类型ObjectNode,它的具体差异是String,Integer和Boolean? StringField如何实现Field接口的handle()方法并实际处理ObjectNode? IMO,objectNodeField应声明为Field 或更好,Field ,以便它可以托管上述类型。

  7. It is nice that you're using recursion to parse the hierarchy of handlers and fields. However, you really think that parsing the Json String each time, and then re-packaging the tree back into String to call the next recursion is the best way?

    您正在使用递归来解析处理程序和字段的层次结构,这很好。但是,您真的认为每次解析Json String,然后将树重新打包回String以调用下一个递归是最好的方法吗?

  8. I could go on but don't want to overwhelm you. Last note, I think you should get familiar with Jackson's feature of parsing a Json String into a multi hierarchy Map. I think it is easier to traverse then Json Nodes.

    我可以继续,但不想压倒你。最后请注意,我认为您应该熟悉Jackson将Json String解析为多层次Map的功能。我认为通过Json Nodes更容易遍历。

#1


1  

First of all, it seems to me that a better place for this question would be the Code Review forum.

首先,在我看来,这个问题的一个更好的地方是代码审查论坛。

However, to get you started, I have few tips:

但是,为了帮助您入门,我提供了一些提示:

  1. As your intuition told you, the code indeed looks "clumsy" or, in other words, not implementing OO principles (or even just plain SW development ones) to good extent.

    正如你的直觉告诉你的那样,代码确实看起来“笨拙”,换句话说,在很大程度上没有实现OO原则(甚至只是简单的SW开发原则)。

  2. I would start by looking at the long branches of the if statememnt, making each branch into separate methods. something like parseField() and parseHandler() and perhaps there are other such blocks of code that can be isolated into separate methods. This will make the parseJsonSchema() method much more readable and debugable (this is, for instance, just plain SW development principle)

    我将首先查看if statememnt的长分支,使每个分支成为单独的方法。像parseField()和parseHandler()这样的东西,也许还有其他这样的代码块可以被分离成单独的方法。这将使parseJsonSchema()方法更具可读性和可调试性(例如,这只是简单的SW开发原理)

  3. The abovementioned principle is aplicable not only in cases of long code blocks, but also in short ones that can be isolated and hide details for the sake of clarity: the if condition that determines if field is Field or Handler. Make it into isField(Map.Entry<String, JsonNode> entry) method. and perhaps you see now why naming it field is not the best option if it can be either Field or Handler. Same comment goes for the handler1 variable. It must have a better more comprehensible name.

    上述原理不仅适用于长代码块的情况,而且适用于可以隔离的短代码并且为了清楚起见隐藏细节:确定字段是字段还是处理程序的if条件。使其成为isField(Map.Entry entry)方法。也许你现在看到为什么命名它字段不是最好的选择,如果它可以是Field或Handler。对handler1变量也有相同的注释。它必须有一个更易于理解的名称。 ,jsonnode>

  4. It is nice that you're using a factory to instantiate Fields. However, other then calling the constructor for a concreate Field implementation, I fail to see what else is your factory doing, because all the parsing of the json and the decision making is done in the parseJsonSchema(). as a rule of thumb, the factory should have one method for each returned type (without generics). So, your factory is returning various Fields, then it should have just createField() that gets a JsonNode and parses what it needs to decide on which implementation to instantiate.

    很高兴您使用工厂来实例化Fields。然而,除了然后调用构造函数进行concreate Field实现之外,我没有看到你的工厂还在做什么,因为json的所有解析和决策都是在parseJsonSchema()中完成的。根据经验,工厂应该为每种返回类型都有一个方法(没有泛型)。因此,您的工厂正在返回各种字段,然后它应该只有createField()获取JsonNode并解析它需要决定实例化哪个实现。

  5. Another OO principle to follow: declare your variable in the inner-most scope that you can. objectNodeField is only accessed inside the branch that handles fields, so put the declaration inside the curly brackets of this branch. do not declare it in the scope of the whole parseJsonSchema(). This makes it easier to understand the scope of the variable and avoid erroneous access outside of the applicable scope.

    要遵循的另一个OO原则:在最内部的范围内声明您的变量。 objectNodeField只能在处理字段的分支内访问,因此请将声明放在此分支的大括号内。不要在整个parseJsonSchema()的范围内声明它。这使得更容易理解变量的范围并避免在适用范围之外的错误访问。

    Now, if you make the the branch into parseField() method, the objectNodeField variable becomes local to that new method. See how it makes the code better in terms of clarity and stability?

    现在,如果将分支设置为parseField()方法,则objectNodeField变量将成为该新方法的本地变量。了解它如何使代码在清晰度和稳定性方面更好?

  6. While we are looking at this variable, I am thinking why did you make its generic type ObjectNode, when its concrete variances are String, Integer and Boolean? how can StringField implement handle() method of Field interface and actually handle ObjectNode ? IMO, objectNodeField should be declared Field<Object> or better yet, Field<?> so it can host the abovementioned types.

    当我们查看这个变量时,我在想为什么你的泛型类型ObjectNode,它的具体差异是String,Integer和Boolean? StringField如何实现Field接口的handle()方法并实际处理ObjectNode? IMO,objectNodeField应声明为Field 或更好,Field ,以便它可以托管上述类型。

  7. It is nice that you're using recursion to parse the hierarchy of handlers and fields. However, you really think that parsing the Json String each time, and then re-packaging the tree back into String to call the next recursion is the best way?

    您正在使用递归来解析处理程序和字段的层次结构,这很好。但是,您真的认为每次解析Json String,然后将树重新打包回String以调用下一个递归是最好的方法吗?

  8. I could go on but don't want to overwhelm you. Last note, I think you should get familiar with Jackson's feature of parsing a Json String into a multi hierarchy Map. I think it is easier to traverse then Json Nodes.

    我可以继续,但不想压倒你。最后请注意,我认为您应该熟悉Jackson将Json String解析为多层次Map的功能。我认为通过Json Nodes更容易遍历。