2

I have a random object and I need to parse Map<String, String>

public class ExternalIncome {

    private Long operationId;

    private OffsetDateTime operationDate;

    private String operationCode;

    private String documentNumber;

    private OffsetDateTime documentDate;

    private String correspondentInn;

    private String correspondentName;

    private String correspondentAccount;
}

I've just created it this way, but I think it's not quite elegant, rather ugly. Also, I need to intercept every iterate of the parsing to hold dynamic fields into Map<String, String> inside of the object.

public static ExternalIncome create(Map<String, String> fields) {
        ExternalIncome externalIncome = new ExternalIncome();
        fields.forEach((k, v) -> {
            switch (k) {
                case "OPER_ID":
                    externalIncome.setOperationId(nullableLong(v));
                    break;
                case "OPER_DATE":
                    externalIncome.setOperationDate(Utils.toOffsetDateTime(v));
                    break;
               etc

Could you help me to find the best way?

  • One possible (but probably not best-performing) solution is to serialize to a JSON string and then deserialize that into your object, using something like Jackson ObjectMapper, or similar offerings from e.g. Gson. – k314159 Feb 17 '21 at 09:41
  • Does this answer your question? [Convert a Map to a POJO](https://stackoverflow.com/questions/16428817/convert-a-mapstring-string-to-a-pojo) – Domenico Sibilio Feb 17 '21 at 09:41
  • @DomenicoSibilio Can I intercept every iteration in this converting? – Денис Бурмистров Feb 17 '21 at 09:58
  • Why? I mean, for what purpose? What does "to hold dynamic fields" mean? What do you need the interceptor to do? – Andreas Feb 17 '21 at 10:50
  • @Andreas I do it for CSV parsing, but opencsv supports only static binding. I mean if the object doesn't include a field, put it into map inside of object "fieldName" -> "value" – Денис Бурмистров Feb 17 '21 at 11:07
  • @ДенисБурмистров let's put it differently. Let's say you have a map ("fieldName" ,"value"). Do you need simple mapping as if map has key X then map it to field X, or it's more complicated? Hard to say without knowing your map structure. – SergeiTonoian Feb 17 '21 at 12:01
  • @SergeiTonoian Yes, I have a map key-value, that includes all fields of object and dynamic fields for business logic. So, I added to the object a map key-value for store that dynamic fields. – Денис Бурмистров Feb 17 '21 at 12:29

2 Answers2

1

You can do it using Jackson's ObjectMapper class , if you are allowed to use third part library.

final ObjectMapper mapper = new ObjectMapper();
final ExternalIncome income = mapper.convertValue(fields,ExternalIncome.class)
Misa D.
  • 183
  • 10
1

I don't see any elegant solution in your case, but you get rid of switch/case by using map where the key is the field name from the fields map and value is BiDirectionalConsumer. Probably not the best solution, but still. Note: be careful with casts and type conversions.

Let's say you have fields map:

Map<String, String> fields = new HashMap<>();   
fields.put("OPER_ID", "3"); 

You can define the second map with field names and operation you want to perform:

HashMap<String, BiConsumer<ExternalIncome, Object>> fieldsOperations = new HashMap<>();
fieldsOperations.put("OPER_ID", (extIncome, valueToSet) -> 
    extIncome.setOperationId(Long.valueOf((String) valueToSet))); //add as many as you want

And then where you iterate over your map with fields:

ExternalIncome externalIncome = new ExternalIncome();
fields.forEach((k,v) -> {        
    BiConsumer<ExternalIncome, Object> operation = fieldsOperations.get(k);
    if (operation == null) {    
        //add to dynamic fields map    
        return;
    }
    operation.accept(externalIncome, v);    
});

Or you can reconsider your data structure to get rid of the idea to have dynamic fields, but idk if it's possible with your use case.

SergeiTonoian
  • 341
  • 2
  • 13