Possible bug while using with complex type objects? (Missing `Map` support)
Closed this issue · 10 comments
Dear @f-lopes,
I just posted a question at StackOverflow, while experiencing a tricky bug in my tests.
https://stackoverflow.com/q/49782283/9457141
Maybe you have a clue if this could be related to using your little helper and hitting some hidden bug?
Your help would be very much appreciated!
Cheers
Oliver
Actually I think this is indeed related to using your helper... 😄
While comparing the HTTPServletRequest
parameters, I notice the following difference:
POST parameters created by your helper
attributes[0]: RQASJc
attributes[1]: ryADf9
defaults: {RQASJc=, ryADf9=}
displayName: svVWw7AUjE
mandatory: {RQASJc=true, ryADf9=true}
multiDoc: true
name: LhzsGo
system: false
POST parameters created by Thymeleaf/Spring combination:
attributes[0]: RQASJc
attributes[1]: ryADf9
defaults[RQASJc]:
defaults[ryADf9]:
displayName: svVWw7AUjE
mandatory[RQASJc]: true
_mandatory[RQASJc]: on
mandatory[ryADf9]: true
_mandatory[ryADf9]: on
multiDoc: true
name: LhzsGo
system: false
When there are optional attributes, the The mandatory[name]
parameter is missing, but the _mandatory[name]: on
is still present, which result in a null entry within the map (which is alright, because I check for this in my validator, etc)._mandatory[name]
keys seem to be ignorable, according to Thymelead + Spring docs
Is this handled differently in JSP than Thymeleaf?
My debug log line I mentioned on StackOverflow seems to be caused by failing to load the property editor in getPropertyEditorFor(Object object)
:
DEBUG org.springframework.beans.BeanUtils - No property editor [java.util.MapEditor] found for type java.util.Map according to 'Editor' suffix convention
Maybe there should be some code to create proper string representations of type Map
? Spring docs at least mention the map[key]
conversion.
Dear @poikilotherm,
Thanks for your feedback.
The tool's goal is to create corresponding HTTP request parameters for a given object using reflection to collect the form fields. I have cloned the repository you mentioned in the StackOverflow issue and the given form doesn't declare a "_mandatory" field, hence the tool cannot generate the corresponding HTTP request parameters.
The error (?) you mentioned in the logs is a Spring one (https://github.com/spring-projects/spring-framework/blob/master/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java#L510).
As you suggest, the issue is maybe related to the way the controller binds these request parameters to the form object? Adding _mandatory
HTTP request parameter makes the test pass.
The conversion is performed here: https://github.com/spring-projects/spring-framework/blob/master/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java#L367
For your information, the next version will support the default property editors registered with Spring MVC.
Dear @f-lopes,
I am not sure I got you correct...
Adding _mandatory HTTP request parameter makes the test pass
Did you just do something like
ResultActions result = mvc.perform(postForm("/admin/doctypes/edit/"+this.valid.getName(), this.valid)
.param("_mandatory[name]", on)
);
to make the tests pass?
Because when I use
ResultActions result = mvc.perform(post("/admin/doctypes/edit/{name}", this.valid.getName())
.param("name", this.valid.getName())
.param("displayName", this.valid.getDisplayName())
.param("system", this.valid.getSystem().toString())
.param("multiDoc", this.valid.getMultiDoc().toString())
.param("attributes[0]", this.valid.getAttributes().get(0))
.param("attributes[1]", this.valid.getAttributes().get(1))
.param("mandatory["+this.valid.getAttributes().get(0)+"]", this.valid.getMandatory().get(this.valid.getAttributes().get(0)).toString())
.param("mandatory["+this.valid.getAttributes().get(1)+"]", this.valid.getMandatory().get(this.valid.getAttributes().get(1)).toString())
.param("defaults["+this.valid.getAttributes().get(0)+"]", this.valid.getDefaults().get(this.valid.getAttributes().get(0)))
.param("defaults["+this.valid.getAttributes().get(1)+"]", this.valid.getDefaults().get(this.valid.getAttributes().get(1)))
);
and thus have no _mandatory[...]
inside, the tests start passing, too (as I wrote above, the _mandatory[...]
is added by Thymeleaf for being on the safe side).
The main difference IMHO seems to be the representation of the Map
- my above code uses the representation mentioned in the (Spring docs about conventions)[https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-beans-conventions].
Could you paste the changed code you came up with here?
Dear @poikilotherm,
I just added a _mandatory
field at runtime to the HTTP request parameters before submitting the form.
The support for Map may need some rework and I will integrate it into the next release (work in progress). As you pointed out in #3 (comment), the Map entries need to be handled as an array.
I am willing to contribute if you are interested. Just let me know...
Thanks for your help, I just committed a fix for this issue: 85225de
This commit just add support for simple Map (<String, String>). Don't hesitate to create a pull request if you want to enhance the Map support.
Thank you for your extension of the class @f-lopes!
I'm going to test this later today and either open a PR or provide feedback here :-)
Should the README state some lines about the limitations/restrictions on usable and supported data types?
Your extension works great!
It also works pretty well for other simple object types like Boolean, etc.
What are your plans on releasing?
Thanks for your feedback!
Should the README state some lines about the limitations/restrictions on usable and supported data types?
I think you're right, I will see how I can integrate it into the README. Feel free to open a pull request if you have ideas about it.
I plan to release a new version this week:
- Will add support for a lot of complex types: the tool will rely on Spring's default property editors.
- I will also rework the conversion process: the strategy is to always give the user the possibility to override this by providing a custom property editor (in case of a bug).