简体   繁体   中英

How to add ObjectNodes to ArrayNodes without overwriting old data

I was trying to call data from Directus API, and return certain data in JSON Format on my localhost.

I'm working on a project where we need to build an API layer.

My code:

public String findAllPersons(HttpServletResponse response, String showFields) throws IOException{

  try {
    // Call to the database (this part is normally not a problem
    String url = "https://cuxhsjf3.directus.app/items/blog";
    PersonRoot personRoot = template.getForObject(url, PersonRoot.class);
    // I used the Objectmapper, since I'm going from normal data to Json.
    ObjectMapper objectMapper = new ObjectMapper();
    ObjectNode personsObject = objectMapper.createObjectNode();
    ArrayNode persons = objectMapper.createArrayNode();
    // The array is going to loop through all the data objects from the database
    for (int i = 0; i < personRoot.data.toArray().length; i++) {
    // I put person objects into an array, and I return this array.
      personsObject.put("id", personRoot.data.get(i).id);
      personsObject.put("firstName", personRoot.data.get(i).firstName);
      persons.add(personsObject);
      System.out.println(persons);
    }
    String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(persons);
    return json;
}
// The 'catch' was omitted as not related to the issue

Expected result:

{
      "id": "050469ed-0501-4506-9951-794b41bf7e7f",
      "firstName": "Elias"
    },
    {
      "id": "0bfb52f7-3656-4202-8c24-2b63eaeca6a9",
      "firstName": "Mathias"
    },
    {
      "id": "3145fb95-afd7-4bc4-a62e-a8622b301db2",
      "firstName": "Brent"
    },
    {
      "id": "5b93c9b1-4bd1-4aa5-a5ca-d46e849cc58f",
      "firstName": "Jef "
    },
    {
      "id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
      "firstName": "Jan"
    }
}

The output I'm getting:

{
    "id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
    "firstName": "Jan"
  },
  {
    "id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
    "firstName": "Jan"
  },
  {
    "id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
    "firstName": "Jan"
  },
  {
    "id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
    "firstName": "Jan"
  },
  {
    "id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
    "firstName": "Jan"
  }
}

As @markspace has pointed out in the comments, you're repeatedly adding the reference to the same ObjectNode into the same JsonArray . When you're modifying this single object, all the elements in the get updated, and what you're getting is data of the very last person replicated multiple time.

You need to move creation of the ObjectNode into the loop, so that a new node would be instantiated for each person:

for (int i = 0; i < personRoot.data.toArray().length; i++) {
    ObjectNode personsObject = objectMapper.createObjectNode(); // move object-creation inside the loop
            
    personsObject.put(...);
    personsObject.put(...);
            
    persons.add(personsObject);
}

Sidenotes

Encapsulation in your custom class PersonRoot is broken. In Java, we use access modifier like protected and private to hide and protect the data within a class instance. And class is supposed to provide behavior which allow interacting with the state of its instances instead of exposing the instance variables directly ( getters are the simplest example of such behavior ). This might look alien to you, if previously you were working with languages like JavaScript, but Encapsulation is one of the crucial parts of Object-oriented programming, and it's a common practice in Java to design classes in such a way so that their data is properly encapsulated.

You might also want to learn about one of the GRASP design-patterns, namely The information expert pattern . Which states that an object containing the data should be provided with behavior that facilitates interaction with the data (it's not the responsibility of the code that make use of this object).

Ie instead of doing this: personRoot.data.toArray().length you can introduce length() method in the PersonRoot class. And instead of writing personRoot.data.get(i) there could be a method like PersonRoot.getPerson(int index) .

You can also make PersonRoot implement Iterable interface, so that it could be used as a source of data within an enhanced for -loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM