Search code examples
javajsonjacksondeserializationobjectmapper

Map dynamic field names while deserializing a JSON to a Java object


I have an interesting problem that I want to solve. This is while I am parsing a response from one of the platforms that we interact with. The response changes based on the User.

Say for User A, I have the following JSON :

{
 "userId": "AA001",
 "AA001_Name": "Username",
 "AA001_Email": "user@gmail.com",
 "AA001_Phone": "000-000-0000"
}

For User B, I have :

{ 
  "userId" : "AA002",
  "AA002_Name" : "Username",
  "AA002_Email" : "user@gmail.com",
  "AA002_Phone" : "000-000-0000"
}

Now, while deserializing, I want to map both of them to the following object, ignoring the field name the json came with :

class User {
  private String userId,
  private String name,
  private String email,
  private String phone
}

It is easy to map the userId, as that's the field in the JSON as well, but what about the custom fields?

Now, I can't use the @JsonProperty as the name of the field is dynamically changing based on the user.

Is there any way this could be accomplished? Please note that I might have several such custom objects like Department, Organization etc, and the platform returns the data in such a manner, meaning the keys have the user-specific information appended.

Any help is appreciated. I am badly stuck at this.


Solution

  • I think you can't do any better than using @JsonCreator:

    class User {
    
        private String userId;
        private String name;
        private String email;
        private String phone;
    
        @JsonCreator
        public User(Map<String, Object> map) {
            this.userId = (String) map.get("userId");
            map.entrySet().stream()
                .filter(e -> e.getKey().endsWith("_Name"))
                .findFirst()
                .ifPresent(e -> this.name = (String) e.getValue());
            // repeat for other fields
        }
    
        // getters & setters (if needed)
    }
    

    You can change the stream by a traditional for each on the map's entry set to optimize performance-wise.