1

Consider the following keys (under_score) and fields (lowerCamel):

keys   = ["opened_by","ticket_owner","close_reason"]
fields = ["openedBy","ticketOwner","closeReason"]

I'm looking for an efficient way in Java to check whether key is in fields, where I expect the following to return true:

fields = ["openedBy","ticketOwner"]

return fields.contains("opened_by"))   //true

My code:

Set<String> incidentFields = Arrays
            .stream(TicketIncidentDTO.class.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toSet()
            );


responseJson.keySet().forEach(key ->{
           
            if (incidentFields.contains(key)) 
            {
                //Do something
            }
        });

I could just replace all lowerCase with underscore, but I'm looking for more efficient way of doing this.

user3819295
  • 861
  • 6
  • 19
  • Does this solve your problem? https://stackoverflow.com/questions/10310321/regex-for-converting-camelcase-to-camel-case-in-java – GhostCat May 10 '21 at 08:39
  • Thanks, but not exactly, I could just replace all lowerCase with underscore, but I'm looking for more efficient way of doing this. Maybe some method which ignore case format or something like that. – user3819295 May 10 '21 at 08:45
  • Sets, Maps, by default call the `equals()` method. There is no "simple" here. Either you implement your very special Set that uses different kind of comparisons, or you bite the bullet and keep multiple sets that have those "transformed" IDs within. And note that ignoring case doesnt really help, as it leaves the "_" around to fail comparisons on. – GhostCat May 10 '21 at 08:50
  • 2
    Could you clarify what you deem too inefficient in "replacing lowerCase with underscore"? As I see it, you have two choices: (1) Initially transforming your fields to be in underscore instead of CamelCase notation, (2) keeping fields as is and instead transforming the keys from underscore to CamelCase during each lookup. Approach (1) is by far the more efficient one if you have relatively few fields and many look ups. – derwiwie May 10 '21 at 09:30

3 Answers3

3

Try with CaseUtils from Commons Text

// opened_by -> openedBy
private String toCamel(String str) {
    return CaseUtils.toCamelCase(str, false, new char[] { '_' });
}

List<String> keys = Arrays.asList("opened_by", "ticket_owner", "close_reason", "full_name");

List<String> fields = Arrays.asList("openedBy", "ticketOwner", "closeReason");

keys.forEach(t -> {
    // check
    if (fields.contains(toCamel(t))) {
        System.out.println(t);
    }
});
nguyenhuyenag
  • 313
  • 5
  • 13
1

If you do not have fields like abcXyz (abc_xyz) and abCxyz (ab_cxyz) (fields with same spelling but combination of different words), then one solution would be to replace the "_" with empty "" and then compare to fieldName using equalsIgnoreCase. Another but similar solution would be to convert each fieldName to lower case and then compare it to the camel case string after replacing the "_" with "". This could possibly eliminate the use of an additional loop when compared to the first approach.


Set<String> fields= Arrays.stream(TicketIncidentDTO.class.getDeclaredFields())
                          .map(Field::getName)
                          .map(String::toLowerCase)
                          .collect(Collectors.toSet());


responseJson.keySet()
            .filter(key -> fields.contains(key.replaceAll("_","")))
            .forEach(key -> {
                // do something..
            });
Gautham M
  • 4,816
  • 3
  • 15
  • 37
1

A simple toCamel method:

private String toCamel(String str) {
    String[] parts = str.split("_");
    StringBuilder sb = new StringBuilder(parts[0]);
    for (int i=1; i < parts.length ; i++) {
        String part = parts[i];
        if (part.length() > 0) {
            sb.append(part.substring(0, 1).toUpperCase()).append(part.substring(1));
        }
    }
    return sb.toString();
}

Now use the very same approach:

keys.forEach(t -> {
    if (fields.contains(toCamel(t))) {
        System.out.println("Fields contain " + t);
    } else {
        System.out.println("Fields doesn't contain " + t);
    }
});

I could just replace all lowerCase with underscore, but I'm looking for more efficient way of doing this.

Use Set as a data structure for keys and fields that is very effective in the look-up. Moreover, it is sutable for this use case since it doesn't make sense to have duplicated keys in JSON.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183