I have nested complex object in my controller:
class ClientDTO {
public InnerClass cl;
public getCl()...
public setCl()...
}
InnerClass contains some primitive data types Integer,String.
My controller just returns this ClientDTO.
On my thymeleaf template I've got :
var client=[[${client}]]
Here client is a ClientDTO value, returned from the controller.
This variable client is serialized into ru.foo.ClientDTO#6543785
which is incorrect.
How can I fix it to receive correct client object in form of json like this: ClientDTO{cl: {....}} ?
It's hard to say where exactly you want this based on your description, but I am assuming your var definition is in a script tag. If so, use
<script data-th-inline="javascript">
to make thymeleaf properly create the variable. Secondly, wrap client like this:
var client = /*[[${client}]]*/ {};
to ensure there is a default and preserve natural templating, with the default being {} or '' or such. From there you can convert to json if you wish.
Related
I have the following method and I need to pass List<UUID> to this Controller method.
#GetMapping("/product/{productUuidList}")
public ResponseEntity<ApiResponse<List<ProductDTO>>> getProductList(
#RequestParam List<UUID> productUuidList) {
// code omitted
}
If I pass the list parameters by separating comma, it is ok. But, I want to pass these list parameters as Json array. When I try to pass uuid parameters in Postman as shown below, I get "productUuidList parameter is missing" error.
{
"productUuidList": ["c849bcbb-c26c-4299-9ca4-dcde56830f5f", "398ec0f8-86c8-400a-93cb-caf47c1ac92d"]
}
So, how should I properly pass uuid array to this Controller method without changing #GetMapping to #PostMapping ?
It won't work like this. Here you are sending a JSON object that looks like this java POJO :
public class MyUUIDWrapper{
private List<UUID> productUuidList;
// GETTERS/SETTERS
}
So Spring is expecting to retrieve a MyUUIDWrapper object in the RequestBody
If you change your code like this it should work :
public ResponseEntity<ApiResponse<List<ProductDTO>>> getProductList(
#RequestParam MyUUIDWrapper uuids) {
NB : If you have troubles deserializing UUIDs (I've never done it before), change List to List. Not the smartest or most beautiful solution, but you can still convert them later in your controller ;)
I have a requirement where am setting up a List of objects as model attribute in spring controller and I need it to assign to an object in angular .ts file.
Here is what I need to do. My java object:
public class Lab {
//some members of the class
}
This is how am adding it to Model:
public String getIndexPage(#RequestParam(value="val") List<Lab> labs, Model model){
model.addAttribute("val", labs);
return "index.html";
}
The corresponding object in Angular named inside lab.ts:
export class Lab {
// same variables as in java
}
And here is the component.ts file where I need to assign the val list:
export class VideoFormComponent implements OnInit {
selectedValues: Lab[] = new Array(4);
ngOnInit() {
this.selectedVideos = "${model.val}"; //assignment statement
}
But here is where am getting the error which says:
Type '"${model.val}"' is not assignable to type 'Lab[]'
What is the correct way to use that list inside the script file?
"${model.val}" is just a string in Typescript.
If model.val is an array of objects that are shaped like Lab[], you can do this.selectedVideos = <Lab[]>model.val.
If model.val is an array already typed as Lab[], you can simply say this.selectedVideos = model.val
I'm not sure what you're trying to do, but I'm assuming you're using Angular HttpClient or websocket or something to first get the data from a server endpoint to the client.
How are you providing the model data to the angular component? If your data comes from a Http request you should create a service that makes the request and then call it from your component and set the result in the selectedValues variable. Or if you are providing the data as an input to the component you should use the #Input decorator. In either case the data is provided externaly to the component. For what I read, you are trying to use a model object that has a val attribute, but you are not providing it anywhere.
Using the Retrofit REST Client library from Square, is there anyway of providing default/constant values for POST/PUT fields in a call.
I know about including constant query parameters by simply including them in the path, but this work for Body parameters.
I have an API that looks similar to:
POST /api/create
type=constanta&value={value}
POST /api/create
type=constantb&value={value}&otherValue={otherValue}
where the second variant requires an additional argument to be supplied. Rather than having a single java method that took all three arguments, I was hoping to be able to elide the constants from the method call, something like:
create(String value);
create(String value, String otherValue);
and have retrofit inject the type argument constant.
Given that adding #FormUrlEncoded can be added to modify how the body is encoded, if it's not natively supported by Retrofit, is there anyway of adding my own annotation and injecting such default values? ( It doesn't appear that RequestInterceptor allows one to modify the body.. ).
Maybe one option would be to send an object, which encapsulates all your values, instead of all string values separately? The object would implement your default values.
For example, you could create a class:
public class CreateObject {
private String type = "constant";
private String value;
private String otherValue;
public CreateObject(String value, String otherValue) {
this.value = value;
this.otherValue = otherValue;
}
}
Your class handles your constant. You could just set it to a default value "constant", like I did above, or set it on the fly in the constructor.
Now all you've to do is to create the object with the values and make the request with Retrofit. Instead of using the string values directly, just pass the object. Your interface could look like this:
public interface CreateService {
#POST("/api/create")
void create(#Body CreateObject create, Callback<CreateObject> cb);
}
The request implementation like this:
CreateObject create = new CreateObject("value", "otherValue");
createService.create(create, new Callback<CreateObject)() {…});
This should include all three of your values in the request body, if they are set. If a value is null, it won't be included in the request body. Based on your two examples above, you would now only need one interface method. Which values are sent is based on the createObject you pass on. For example, if you set otherValue as null, it won't be part of the request body.
My examples were modified from: https://futurestud.io/blog/retrofit-send-objects-in-request-body/
Is it possible for you to use Guava or Java 8 Optional as second argument in method? Then if that argument will be absent you can just ignore it
I'm trying out apache-camel, and I've set up a basic route that calls an http service via http4 component, transforms the result via unmarshal().json(JsonLibrary.Jackson), and then prints out part of the response in a bean component.
The problem I'm having is that it blows up at runtime when it gets to the json unmarhsaller:
No type converter available to convert from type: java.util.HashMap to the required type: com.xxx.MyType
The response is of this format:
{"data":[{"x":"y"},{"x":"z"}]}
And my object model is like:
#lombok.Data
class Response {
private List<Elem> data;
}
#lombok.Data
class Elem {
private String x;
}
So it would appear that the unmarshaller thinks the response is a hash map, whereas I want it to unmarshal into an object structure. Is there a way to get it to do what I want?
Found the answer, posting in case anyone else runs into this. The route builder should be setup like:
from("direct:start").to("http4://...").unmarshal().json(JsonLibrary.Jackson,com.xxx.Response)
.to("bean:com.xxx.MyResponseEchoer")
I.e. pass the class type to the json method.
I'm working on converting a legacy project to Spring (trying to adjust little as possible for now) and I'm running into a small issue with mapping/translating legacy parameters to a model attribute object. I may be completely wrong in thinking about this problem but it appears to me that to translate a parameter to a specific model attribute setter is to pass in the request parameter through a method for creating a model attribute and manually call the correct setter:
#ModelAttribute("form")
public MyForm createMyForm(#RequestParameter("legacy-param") legacy) {
MyForm myForm = new MyForm();
myForm.setNewParam(legacy);
return myForm;
}
I don't necessarily want to change the request parameter name yet since some javascript and JSPs are depending on it being named that way but is there any way to do something like this? Or is there a different way to map/translate request parameters to model attributes?
public class MyForm {
#ParameterName("legacy-param")
private String newParam;
public void setNewParam(String value) { ... }
public String getNewParam() { ... }
}
#Controller
public class MyController {
#RequestMapping("/a/url")
public String myMethod(#ModelAttribute("form") MyForm myForm, BindingResult result) { ... }
}
The way you've written that model attribute method is indeed odd. I'm not entirely clear what you're actually trying to do.Assuming there are many parameters, you're going to end up with an awful lot of instances of MyForm in your ModelMap. A more 'normal' way to create model attribute would be like this:
#ModelAttribute("legacyParamNotCamel")
public MyForm createMyForm(#RequestParameter("legacy-param-not-camel") String legacy) {
return legacy;
}
Then in the JSP you can refer to it directly in expression language. e.g.,
<c:out value="${legacyParamNotCamel}"/>
If you want to put them onto a form backing object, you need to do it all in a single method that creates the object, not make new copies of it in each method. (assuming your form has more than a single parameter associated with it.)
--
It seems like what you're really trying to do though is translate the parameter names in the request before the web data binder gets ahold of it, so that you can bind oddly named parameters onto a java bean? For that you'll need to use an interceptor that translates the names before the binding process begins, or make your own subclass of the databinder than can take a property name translation map.
You placed the #ModelAttribute at the Method Level but the intention seems to be more of a formBackingObject hence we should be dealing at the Method Parameter Level
There's a difference.
I put up an explanation here on my blog along examples at Spring 3 MVC: Using #ModelAttribute in Your JSPs at http://krams915.blogspot.com/2010/12/spring-3-mvc-using-modelattribute-in.html