5

I'm working on a project where I need to map from a hierarchical Map<String, Object> where the second parameter is expected to be a String or Map<String, Object>. Thus far, ModelMapper has worked awesome, but I'm having trouble with a specific conversion. Given the following, where Model is simply a marker interface:

class Client implements Model {
    String firstName;
    String lastName;
    List<Organization> organizations = new ArrayList<>();
}

Assuming Organization implements my marker interface Model but is otherwise arbitrarily structured, I would like to be able to map the following to Client:

Map source = new HashMap(){{
    put("firstName", "John"),
    put("lastName", "Smith"),
    put("organizations", new HashMap(){{
        put("0", new HashMap(){{
            put("id", "1234");
        }});
        put("abc", new HashMap(){{
            put("id", "5678");
        }});
    }});
}};

In summary: how might I go about having ModelMapper drop the map keys and use only the value list when pushing into the organizations property? Failing this, the organizations property comes up empty. You may assume that I have a good reason for wishing to do this, and a poor example!

Thanks in advance for your input!

Edit

I attempted to build a Converter that would manage converting from a Map to a Collection<Model> to no avail. Given:

new Converter<Map, Collection<DataTransportObject>>() {
    @Override
    public Set convert(MappingContext<Map, Collection<DataTransportObject>> context) {
        LOG.debug("Here");
        Set<DataTransportObject> result = new HashSet<>();
        return result;
    }
}

There are two problems with this:

  1. Apparently ModelMapper doesn't look at inheritance, therefore when any implementation of Map is given as the source, the converter is not run. If, for example, I change the converter to accept HashMap and pass a HashMap as the source, then it works.
  2. context.getGenericDestinationType() returns List or Set classes without the generic information. How then does ModelMapper manage to construct complex model graphs under normal circumstances?
ironhardchaw
  • 149
  • 3
  • 10
  • It seems like you're asking for different things in different parts of your question. Do you want to convert your Map to a `Client` instance, or do you want to convert it to a List? – VGR Nov 28 '14 at 17:53
  • The given map should be converted to a `Client` instance. But as it stands, ModelMapper will not handle the `organizations` property and will leave it blank. I want to get ModelMapper to push the map value list into the `organizations` property. – ironhardchaw Nov 28 '14 at 18:03
  • I think you need BeanUtils or ObjectMapper. You can see answer in [http://stackoverflow.com/questions/739689/how-to-convert-a-java-object-bean-to-key-value-pairs-and-vice-versa][1] [1]: http://stackoverflow.com/questions/739689/how-to-convert-a-java-object-bean-to-key-value-pairs-and-vice-versa – Andrey Pushin Nov 28 '14 at 20:17
  • I read over that answer, but I'm not sure that I found what I'm looking for. I'm looking at converting a map to an object, not the other way around. I'll investigate the use of ObjectMapper, as I've already tried BeanUtils. – ironhardchaw Nov 28 '14 at 20:21

1 Answers1

0

In your case I think you can use additional setter for Pojo class. And then for convert map to object use libraries as ObjectMapper/BeanUtils/... . For example:

void setOranizations(Map<String, Organization> map) {
    this.organizations = map.values();
}
  • The point of this question is to be able to shoehorn that map into a collection as a list of values. The point being that I'm given a hierarchical map with arbitrary keys and arbitrary values, and that I need to be able to just drop the keys from the map and use the value list. – ironhardchaw Nov 28 '14 at 20:40
  • May be you can add additional setter to your model. For example setOrganizations(Map map) {this.organization = map.values}; – Andrey Pushin Nov 28 '14 at 20:50
  • Can't believe I didn't think of that! It's not quite what I'd like, but certainly a valid solution. I tried it out with ModelMapper in addition to ObjectMapper and it works for both. If you will turn your comment into an answer, I will mark it specifically as the accepted answer, as it also applies to the original question without changing libraries. – ironhardchaw Nov 28 '14 at 20:59
  • Just want to point out that Jackson, and subsequently ObjectMapper, requires the use of `@JsonSetter` to annotate the the setter, otherwise the public field will be used instead. ModelMapper seems to use the setter rather than the field when given the option. – ironhardchaw Nov 29 '14 at 22:52