0

I'm developing a springboot application.

I've a class with the following fields

class MyClass
{
  String s1;
  String s2;
  String s3;
  String s4;

  //getters setters constructors
}

I'm calling an API which in turn calls a service.

public String myService()
{
    JSONArray arr1 = new JSONArray();
    for (Items item : itemsList) 
    {
      JSONObject itemObj = new JSONObject();
      itemObj.put("s1","Value1");
      itemObj.put("s2","Value2");
      itemObj.put("s3","Value3")
      itemObj.put("s4","Value4");

      arr1.put(itemObj);
    }

    JSONObject out = new JSONObject();
    out.put("total_Items", arr1);
    return out.toString();  // this is org.json.JSONObject
}

This way I'm able to get the excel with the reordered members as the columns when a button is clicked at the frontend angular app.

What I want is the order of the the members in the columns remains preserved when exporting into an excel sheet.

s1|s2|s3|s4 //as per the above example

I've many other services as well, which return different types of Objects(apart from the MyClass mentioned here) so I wanted to return the elements in the order defined (as per the order of members in the class) from the backend itself.

I know that JSON does not allow us to preserve the order as it internally uses a HASHMAP.

Is there a way to return a JSON response such that the order remains same as that of the class members?

I also tried using GSON in the below way.

public String myService()
{
  MyClass itemsArray[] = new MyClass[itemsList.size()];
  int i=0;
  for (Items item : itemsList) 
  {
    MyClass itemObj = new MyClass();
    itemObj.setS1("Value1");
    itemObj.setS2("Value2");
    itemObj.setS3("Value3")
    itemObj.setS4("Value4");

    itemsArray[i]=itemObj;
  }
  Gson gson = new Gson();
  return gson.toJson(itemsArray);  // this is java.lang.String
}

In this scenario I'm able to get the API response(on POSTMAN) with the elements in ordered fashion but when exporting on the frontend angular app it freezes at the downloading screen.

I tried doing conversion to JSONObject and other things randomly but was not able to make the code work properly.

Is there anyway the problem can be resolved at the backend...or something needs to be done at the frontend only?

Thanks in advance.

sleepy_soul
  • 49
  • 1
  • 10
  • Replace the JSON library with Jackson and use [@JsonPropertyOrder](https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-annotations/latest/com/fasterxml/jackson/annotation/JsonPropertyOrder.html). – Chin Huang Aug 05 '22 at 18:18
  • I did this.....but the moment after after theb loop ends and puts into JSONObject.... JSONObject out = new JSONObject(); out.put("total_Items", arr1); return out.toString(); // this is org.json.JSONObject .......the order of members is lost foreach object(as seen on the API response on postman). – sleepy_soul Aug 06 '22 at 05:11
  • I meant get rid of Gson and use Jackson for all your JSON processing. If you really want to keep Gson, then you need to create a [custom JSON serializer](https://stackoverflow.com/questions/6365851/how-to-keep-fields-sequence-in-gson-serialization). – Chin Huang Aug 06 '22 at 05:19
  • I tried using the @JsonPropertOrder in the first implementation show here....without GSON – sleepy_soul Aug 06 '22 at 05:52

1 Answers1

1

If you want to do using DataStructure use LinkedHashMap as given below. It will serialize in inserted order.

public static void main(String args[]){
        ObjectMapper mapper = new ObjectMapper();
        Map<String, String> itemObj = new LinkedHashMap<>();
        itemObj.put("s91","Value1");
        itemObj.put("s2","Value2");
        itemObj.put("s3","Value3");
        itemObj.put("s4","Value4");
        try {

            String jsonString = mapper
                    .writerWithDefaultPrettyPrinter()
                    .writeValueAsString(itemObj);
            System.out.println(jsonString);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
{
  "s91" : "Value1",
  "s2" : "Value2",
  "s3" : "Value3",
  "s4" : "Value4"
}

If you want to serialize in sorted order the use TreeMap, it will serialize in sorted key

 Map<String, String> itemObj = new TreeMap<>();
...
{
  "s2" : "Value2",
  "s3" : "Value3",
  "s4" : "Value4",
  "s91" : "Value1"
}

This can be done using Jackson library using the @JsonPropertyOrder annotation.

You can define the order of elements as given below above class @JsonPropertyOrder({ "s3", "s2", "s1", "s4"})

Refer to below a working example

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.istack.NotNull;
import java.io.IOException;
import java.util.UUID;

@JsonPropertyOrder({ "id", "password", "name", "email", "enabled" })
public class UserResource {
    private UUID id;
    @NotNull
    private String name;
    @NotNull
    private String email;
    private boolean enabled;
    private String password;

    public UserResource(UUID id, String name, String email, boolean enabled, String password) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.enabled = enabled;
        this.password = password;
    }

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public static void main(String args[]){
        ObjectMapper mapper = new ObjectMapper();
        try {
            UserResource student = new UserResource(UUID.randomUUID(), "sheel", "sheel@c4c.com",true, "$$$$$$%%##^^$DSGHHH");
            String jsonString = mapper
                    .writerWithDefaultPrettyPrinter()
                    .writeValueAsString(student);
            System.out.println(jsonString);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

and output as given below

{
  "id" : "fbfcd21d-731e-4acb-9fec-90a499e47cc9",
  "password" : "$$$$$$%%##^^$DSGHHH",
  "name" : "sheel",
  "email" : "sheel@c4c.com",
  "enabled" : true
}
Sheel Prabhakar
  • 409
  • 2
  • 6
  • If I've multiple student objects and then store into some data structure...then will also be the order preserved when received at the frontend??? The reason I'm asking this because I've to send multiple objects and the requirement is such that the order needs to be preserved....and also there are different services which will return different types of objects with varying number of fields and for all the order needs to be preserved. – sleepy_soul Aug 06 '22 at 13:33
  • I update using LinkedHashMap -> will serialize in inserted order and TreeMap -> will serialize in sorted key order – Sheel Prabhakar Aug 08 '22 at 15:54