Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support for Mapping from Map<String, ???> to Bean #1075

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
twothe opened this issue Feb 15, 2017 · 24 comments · Fixed by #2471
Closed

Support for Mapping from Map<String, ???> to Bean #1075

twothe opened this issue Feb 15, 2017 · 24 comments · Fixed by #2471
Labels
Milestone

Comments

@twothe
Copy link

twothe commented Feb 15, 2017

Refering to Stack-Overflow

The situation is: I have a REST service that must be called with a huge amount of parameters (as by customer request) and those should be stored in a database. The easiest way to do that would be to take the parameter map and map that to an entity object. As it is about the same type of code to map from an object to and object or from a map to an object I assume it should not be too difficult to allow mapping like this:

public MyEntity mapToEntity(final Map<String, String> parameters);

Essentially that should turn into code like this:

myEntity.setName( parameters.get("name") );
myEntity.setReferrer( stringToReferrer( parameters.get("referrer") ) );
//...

It would be nice to have other variable types supported as well, like Map<String, Object>, but I am not sure at which point it becomes too complicated.

@gunnarmorling
Copy link
Member

Yes, I've been thinking about this, too. There also is #717 which is related. It'd require quite some changes I reckon but I'd be sympathetic to adding this. For Map<String, Object> we'd need a new property on @Mapping for (optionally) specifying the type of the property in the map.

@filiphr
Copy link
Member

filiphr commented Feb 18, 2017

@gunnarmorling I am not sure that we will need to do something special to support mapping from Map<String, Object> into a bean. If you look at the map as a bean that has a getter that returns an Object, then it is not different than what we have now.

We already have a mechanism that allows us to map Object to B. The user will have to provide the mapping classes from Object to their respective types (something that needs to be done for String also). I am not sure how it'll work for the reverse type, but I think that it can be done in a similar way.

@Raild
Copy link

Raild commented Feb 21, 2017

I've tried to do it in the following way:

@Mapping(expression = "java(parameters.get(\"name\"))", target = "name")
public MyEntity mapToEntity(final Map<String, String> parameters);

But is it possible to convert the value if the MyEntity.name type is boolean (without calling Boolean.parse(...) manually)?

sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 8, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 8, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 8, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 9, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 9, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 9, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 9, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 9, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 9, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Mar 9, 2019
@filiphr filiphr added this to the 1.4.0 milestone Sep 18, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Sep 22, 2019
sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Sep 28, 2019
@ft0907
Copy link

ft0907 commented Dec 14, 2019

I have a similar requirement now, and I need to directly map the map to the bean. I don't know if there is any information on the advancement of this function or if there are other solutions?

@markbanierink
Copy link

We have this requirement too. However, for us it is important that this Map to Object mapper would behave in a PATCH manner, updating only the object fields that are provided in the map and ignoring the rest. Is that also the intention of this feature?

@filiphr
Copy link
Member

filiphr commented Jan 27, 2020

@markbanierink the idea for this feature is to support all the other functionalities that MapStruct has. So if you are using @MappingTarget with NullValuePropertyMappingStrategy#IGNORE it would behave as you need.

We have not yet discussed the length of the implementation, but I envision that it would generate something like:

public interface CustomerMapper {

    public void updateCustomer(@MappingTarget Customer customer, Map<String, Object> parameters) {

        if (parameters.contains("name")) {
            target.setName(parameters.get("name"));
        }
    }

}

Of course with proper conversions.

sjaakd pushed a commit to sjaakd/mapstruct that referenced this issue Jan 31, 2020
@braeluca
Copy link

Will it be possible to map a map with a nested map?
e.g.

Map<String,Object> map = new HashMap<>();
Map<String,Object> nestedMap = new HashMap<>();
        
nestedMap.put("name","Name");
map.put("nestedMap",nestedMap);

and refere it like

@Mapping(source = "map.nestedMap.name", target = "name")

@filiphr filiphr modified the milestones: 1.4.0.Beta1, 1.4.0 May 30, 2020
@ckosmowski
Copy link
Contributor

I saw that there was a beta release for 1.4.0. I am constantly stalking this issue because it would really be a great help to have this feature on 1.4.0. Is there any change that this feature makes it into the release?

@filiphr
Copy link
Member

filiphr commented Jun 13, 2020

Whether this will make it into the final release or not depends on the time we have to implement it or not. There is PR #1744 with some initial steps, but it is not ready.

Anyways if this does not make it into the final release we will try to include it in the next one. This is one of the most requested feature and I agree that it makes sense to have support for this. We need to iron out the implementation, since I want to support JsonNode from Jackson in a similar way.

We are also aware that we've been rather slow in doing new releases and that's mostly because of lack of time. We are trying to improve on this and release more frequently in the future.

@ckosmowski
Copy link
Contributor

Hi i could probably help with the lack of time problem :-) I would be glad to file a pull request on this but i was confused about the state of this issue because of the existing pull request and the duplicates. The pull request now also seems to be closed.

Could you clarify the state here? Is there any usable code to get closer to the solution? Or could i start over with a completely pull request?

@ckosmowski
Copy link
Contributor

Hi, i just wanted to check if there is any progress on this topic i am really looking forward to this feature

@sjaakd
Copy link
Contributor

sjaakd commented Dec 29, 2020

@ckosmowski no.. there's not any progress on this issue. I planned to work on it, but got side-tracked in a few other issues.

@ckosmowski
Copy link
Contributor

Okay thanks.

I'd like to know what you think about an approach i was thinking about looking at the code. Keeping in mind that the BeanMappingMethod class and its post processing has plenty of features already i was thinking about the following approach:

  • In the first round if you encounter a method that maps from a Map to a Bean, generate a fake mapping method, that defers to a (not yet existing) mapper.
  • Generate a "WrapperBean" that is backed by the Map. Generate getter methods here for all writable properties of the target bean
  • Generate a Mapper that takes the WrapperBean as its input and maps to the target bean of the original mapper, from here on, everything can go through the existing BeanMappingMethod way

What do you think?

@sjaakd
Copy link
Contributor

sjaakd commented Dec 29, 2020

Okay thanks.

I'd like to know what you think about an approach i was thinking about looking at the code. Keeping in mind that the BeanMappingMethod class and its post processing has plenty of features already i was thinking about the following approach:

* In the first round if you encounter a method that maps from a Map to a Bean, generate a fake mapping method, that defers to a (not yet existing) mapper.

* Generate a "WrapperBean" that is backed by the Map. Generate getter methods here for all writable properties of the target bean

* Generate a Mapper that takes the WrapperBean as its input and maps to the target bean of the original mapper, from here on, everything can go through the existing BeanMappingMethod way

What do you think?

I guess that was the original idea that I came up with as well. The history of this PR probably shows.

Anyway. We (@filiphr and myself) decided not to pursue the 'WrapperBean' idea and instead copy the BeanMappingMethod to a new class BeanToMapMappingMethod and pull everything out that we don't need (e.g. Map side nesting). So to make Map to Bean native to MapStruct rather than generating a Wrapper.

One of the biggest drawback was that it requires to construct an additional class runtime (performance), but also keeping track of that class for reuse in other mappings.

@ckosmowski
Copy link
Contributor

Okay, did you start with that already or should i give it a try? :-)

@sjaakd
Copy link
Contributor

sjaakd commented Dec 29, 2020 via email

ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Dec 30, 2020
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Dec 30, 2020
@ckosmowski
Copy link
Contributor

ckosmowski commented Dec 30, 2020

I didn't know that this would be shown here directly. But as you can see, i gave it a try. I tried a slightly different approach. When i tried to copy BeanMappingMethod i realized that this would result in heavy code duplication now and in the need to implement every feature twice in the future, so i tried to add a new Type of Accessor here which seems to work.

Unfortunately i was not able to the full maven pipeline and integration tests running. The build complains about circular dependencies.

A review would be appreciated. Is this a promising approach or rather something to throw away? :-)

https://github.com/ckosmowski/mapstruct/tree/issues/1075

EDIT: Seems like i managed to remove the circular package dependency, looks better now

ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Dec 30, 2020
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Dec 30, 2020
@sjaakd
Copy link
Contributor

sjaakd commented Dec 30, 2020

Hey Chris, your solution looks surprisingly simple to me 😄 . Could you make a PR out of this, so that also @filiphr can have a look at the implementation as well.

I did make a PR for it in the past (its still there open for inspiration 😄 ).

I guess the best thing you could do at this moment is to invest in unit tests.. With that I mean, all kinds of combinations of update methods, create methods, mapping strategies. Also I would like to to see what happens if you cannot make a direct mapping from a map to a target.. E.g. is an available mapping method / typeconversion called correctly? Perhaps its the obvious thing.. but unit test make up a lot of our invested effort and will prove valuable always.

I do have some comments: e.g. I would expect different accessors than MAP e.g. MAP_GET MAP_PUT and MAP_CONTAINS (so they can be customized in the future by means of SPI), But lets do that on the PR branch.

ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Dec 30, 2020
…or update method and default values, use default type for untyped maps
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Jan 8, 2021
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Jan 16, 2021
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Jan 16, 2021
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Jan 17, 2021
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Jan 22, 2021
ckosmowski added a commit to ckosmowski/mapstruct that referenced this issue Jan 22, 2021
@jonsalvas
Copy link

Any updates on this? We could really benefit from this in our current project :-)

@ckosmowski
Copy link
Contributor

ckosmowski commented Apr 13, 2021

Actually in #2317 this is basically implemented and working. However like most of us because of the limited time i am granted to spend on open source projects during work time. It seems like there are still some unit tests missing, but unfortunately i am out of sprint time for this (for now). Whould you like to take over? Or maybe @sjaakd and @filiphr have the chance to finish it (Documentation?) We're almost there :-)

@ordisilent
Copy link

You can seek to join the spring team, so that better compatible with Java, better promotion

filiphr pushed a commit to filiphr/mapstruct that referenced this issue Jun 5, 2021
@filiphr filiphr mentioned this issue Jun 6, 2021
2 tasks
filiphr added a commit to filiphr/mapstruct that referenced this issue Jun 26, 2021
filiphr added a commit that referenced this issue Jun 27, 2021
@filiphr filiphr changed the title Please add a feature to map from java.util.map to an object Support for Mapping from Map<String, ???> to Bean Jun 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.