Customize mapping request parameters and fields inside the DTO ?
Asked Answered
A

3

11

I have the following class:

public class MyDTO { 

       private String kiosk;
       ...
}

and following url:

http://localhost:1234/mvc/controllerUrl?kiosk=false

and following controller method:

@RequestMapping(method = RequestMethod.GET, produces = APPLICATION_JSON)
@ResponseBody
public ResponseEntity<List<?>> getRequestSupportKludge(final MyDTO myDTO, BindingResult bindingResult) {
    ...
}

Now it is working nice and boolean field resolves properly.

Now url parameter has changed like this:

http://localhost:1234/mvc/controllerUrl?new_kiosk=false

I don't want to change parameter name inside the DTO. Is there way to say spring to understand that new_kiosk request parameter value should be put into kiosk field ?

Androw answered 5/5, 2015 at 12:59 Comment(6)
What is the data type(JSON/XML etc) that you are accepting from front end?Floristic
@RE350 It is just get parameters. url like this controllerUrl?new_kiosk=falseAndrow
I strongly suggest a read of the java bean specification. A property is just the name of the getter/setter how the field is named internally doesn't matter. If your field is named foo and you have a setBar method that sets the value of foo you have a bar property. Property != field.Ringhals
@M. Deinum it is surprise for me. I always use IDE set get generator. By default it generates set and get methids accordin field names.Androw
@M. Deinum Do you suggest to create methods with names setNew_kiosk and getNew_kiosk ?Androw
Ofcourse it does as that is in 99% of the cases correct. However as mentioned the property name doesn't have to match the field name (I strongly suggest a read of the java beans spec. which explains all of that).Ringhals
I
17

Apart from setting an additional setter you can hande the case by making a custom argument resolver. There's a few ways you can go about it, but there's already a well discussed post. If I were you I would focus on the jkee's answer. Follow it step by step, and than all you should do is annotate your DTO with something like,

public class MyDTO { 

       @ParamName("new_kiosk")
       private String kiosk;
       ...
}

Note that even if you can't change MyDTO class, you can still follow a custom resolver route. In this post I've answered how you can write a parameter type annotation. Combining the two post you can easily come up with an annotation e.g. @ParamMapper that would define the mapping from request to properties. Think of something like

 getRequestSupportKludge(@ParamMapper("new_kiosk;kiosk") MyDTO myDTO, BindingResult bindingResult)
Ildaile answered 10/5, 2015 at 6:14 Comment(0)
T
4

There different ways to do that.

If you can change MyDTO class the simplest way is to add a setter as suggested by M.Deinum :

public class MyDTO { 

       private String kiosk;
       ...
       public void setNew_kiosk(String kiosk) {
           this.kiosk = kiosk;
       }
}

That way, you can process http://localhost:1234/mvc/controllerUrl?kiosk=false as well as http://localhost:1234/mvc/controllerUrl?new_kiosk=false

If you are not allowed to do that (because the DTO is part of a library you are not allowed to change or ...), you can use a filter mapped to /mvc/controllerUrl, that would wrap the request with a custom HttpServlerRequestWrapper that will override following methods :

String  getParameter(String name)
Map<String,String[]>    getParameterMap()
Enumeration<String>     getParameterNames()
String[]    getParameterValues(String name)

calling the underlying request methods and processing the special parameter name. Example :

String[]    getParameterValues(String name) {
    String[] values = req.getParameterValues(name); // req is the wrapped request
    if ("kiosk".equals(name) && (values == null) {  // will accept both names
        values = req.getParameterValues("new_kiosk"); // try alternate name
    }
    return values;
}

This will be much harder to write and test, so only go that way if you cannot modify MyDTO class.

You could also try to use a custom implementation of WebBindingInitializer. From Spring Framework Reference Manual :

To externalize data binding initialization, you can provide a custom implementation of the WebBindingInitializer interface, which you then enable by supplying a custom bean configuration for an AnnotationMethodHandlerAdapter, thus overriding the default configuration.

Beware : the recommended usage of that is to register custom editors for a whole application - not your use case. And Spring Framework is oftern described as easy to extend but not to override. Caveat emptor ...

Summary : try to use method 1, if you cannot, then use method2, and only try method3 if you have other reasons to use a custom WebBindingInitializer

Tc answered 10/5, 2015 at 8:28 Comment(0)
R
-1

You can use @JsonProperty on the field of the DTO for mapping it with the request JSON, if the field name in the request is different from the field defined in the DTO.

Robbierobbin answered 10/10, 2022 at 18:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.