How to get values to ArrayList of Class, from jsp page using jstl tag? - spring

This is my first VO class member variable:
private List<ProgramToStudyMap> programToStudyMaps;
And here is ProgramToStudyMap Class:
public class ProgramToStudyMap {
private Long studyId;
private List<Long> programId;
}
And my jsp code is,
<form:checkbox path="programToStudyMaps[0].studyId" />
But it's giving error like,
org.springframework.beans.NotReadablePropertyException: Invalid property 'programToStudyMaps[0]' of bean class [java.util.ArrayList]: Bean property 'programToStudyMaps[0]' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
This is my controller:
#RequestMapping(value = RequestMap.MAINTENANCE_STUDY_PROGRAMS, method = RequestMethod.POST)
public #ResponseBody JsonResponse maintananceStudyProgramsSave(#ModelAttribute ProgramToStudyVo programToStudyVo) {
JsonResponse jsonResponse = new JsonResponse();
try {
System.out.println("---------- "+programToStudyVo.getProgramToStudyMaps().get(0).getStudyId());
System.out.println("---------- "+programToStudyVo.getProgramToStudyMaps().get(0).getProgramId());
System.out.println("------------- "+programToStudyVo.getProgramToStudyMaps().get(1).getStudyId());
System.out.println("------------- "+programToStudyVo.getProgramToStudyMaps().get(1).getProgramId());
jsonResponse.setStatus(RhoConstants.JSON_SUCCESS);
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage());
}
return jsonResponse;
}
How can I resolve this.?

The problem is you are sending the json response from the server and trying to display the results using spring:form tags , which cant be done as though.
You can do a alternative method if you want to end up with json, handle the response using javascriptand populate the checkbox values
Else if you wish to go with spring:form you need to add the values to the Model using model.addAttribute() method and display it using path property
Also remember path property should match the property names of your model class.
IMHO , take this tutorial to have some idea before you start with.

Related

resilience4j circuit breaker change fallback method return type than actual called method return type

I am trying to learn Spring Boot microservices. Now I am trying to implement circuit breaker with resilience4j if any of my called service is off.
If I set the fallback method return type as like the actual method return type than it works fine but I can't show the information that my service is off. Because it then send the response null in object's fields. But if I change the return type to String on actual method and also in fallback then I will not be able to get the object value as JSON.
Is it possible to return as string something like Branch service is down!.. with my fallback method and if OK then get the object value as JSON from actual called method? My attempts are below:
My controller method:
#GetMapping("/getById/{id}")
#CircuitBreaker(name = "default", fallbackMethod = "employeeFallback")
public ResponseModelEmployee getEmployee(#PathVariable("id") Long id) {
return employeeService.findByEmployeeId(id);
}
My fallback method in controller:
public ResponseModelEmployee employeeFallback(Long id, Exception ex) {
return new ResponseModelEmployee();
}
My service method called from controller:
public ResponseModelEmployee findByEmployeeId(Long id) {
ResponseModelEmployee empDetails = new ResponseModelEmployee();
...
Branch branch = restTemplate.getForObject("http://BRANCH-SERVICE/branch/getById/" +
employee.get().getBranchId(),
Branch.class);
...
return empDetails;
}
My desire method as fallback:
public String employeeFallback(Long id, Exception ex) {
return "Branch Service is down";
}
If I set my desire method for fallback then it gives the following error:
java.lang.NoSuchMethodException: class com.example.employee.VO.ResponseModelEmployee class com.example.employee.controller.EmployeeController.employeeFallback(class java.lang.Long,class java.lang.Throwable) at io.github.resilience4j.fallback.FallbackMethod.create(FallbackMethod.java:92) ~[resilience4j-spring-1.7.0.jar:1.7.0] ....
Resilince4j expects the fallback method to have the same return type as of the actual method.
Documentation says:
It's important to remember that a fallback method should be placed in
the same class and must have the same method signature with just ONE
extra target exception parameter).
If there are multiple fallbackMethod methods, the method that has the
most closest match will be invoked, for example:
If you try to recover from NumberFormatException, the method with
signature String fallback(String parameter, IllegalArgumentException
exception)} will be invoked.
You can define one global fallback method with an exception parameter
only if multiple methods has the same return type and you want to
define the same fallback method for them once and for all.
So, you cannot directly change the return type to a different one.
You can try few suggestions:
Add #CircuitBreaker and fallback to the service method.
Change return type of service method and fallback method to Object.
One more way could be , you can keep the return type as it is but add a String type message object to response model ResponseModelEmployee. Then set message string to it during fallback.
Another solution could be to return ResponseEntity from the from the method where rest call is made and in the fallback method use ResponseEntity<?> as response object.
you can use Object as a return type
in my case for example:
#GetMapping("/getUser/{id}")
#CircuitBreaker(name= something , fallbackMethod = "ContactsServiceDown")
public ResponseEntity<User> getDetailsById(#PathVariable(id)){
//some logic
return new ResponseEntity<User>(user , HttpStatus.OK);
}
public ResponseEntity<Object> ContactsServiceDown(int id , Exception e){
//some logic
return new ResponseEntity<Object>("ContactsServersDown", HttpStatus.Forbidden)
}
or in returnType ResponseEntity<> leave the type Field empty, hopefully it may work!

Using MvcUriComponentsBuilder::fromMethodCall with String as the return type

I'd like to use the MvcUriComponentsBuilder::fromMethodCall method to build URLs from my controllers. I normally have a String return type (which returns the view name) and a Model instance as method parameter in my controller methods like:
#Controller
public class MyController {
#RequestMapping("/foo")
public String foo(Model uiModel) {
uiModel.addAttribute("pi", 3.1415);
return "fooView";
}
}
I try to generate a URL e.g. like:
String url = MvcUriComponentsBuilder.fromMethodCall(on(MyController.class).foo(null)).build().toUriString();
This leads to this exception:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class java.lang.String
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) ~[spring-webmvc-4.1.4.RELEASE.jar:4.1.4.RELEASE]
This happens because the String return type wants to get proxied, but can't as a final class.
What's a way to overcome this? I'd like to keep the String as a return type and get the Model as input from a parameter in my controller methods because IMHO it's way easier than handling a ModelAndView instance in every controller method.
fromMethodCall uses CGLIB proxy in the process which is why you run into the issue. This article details why.https://github.com/spring-projects/spring-hateoas/issues/155. Try using fromMethodName if you want to maintain the String return types.
MvcUriComponentsBuilder.fromMethodName(MyController.class, "foo", new Object()).build();
Consider changing the signature of the method to return Spring's ModelAndView vs. returning String. For example:
#Controller
public class MyController {
#RequestMapping("/foo")
public ModelAndView foo() {
return new ModelAndView("fooView", "pi", 3.1415);
}
}
With this refactored signature, the corresponding fromMethodCall invocation would look like this:
UriComponents uri = fromMethodCall(on(MyController.class).foo()).build();

Spring Mvc ModelAttribute with referencing name is not working?

I want to to create different #Entity entities within the same Controller.
#RequestMapping(value="create", method=RequestMethod.GET)
public String GET(Model model) throws InstantiationException, IllegalAccessException
{
Class<?> clazz = ????; // a Random POJO is chosen, i want to use POJOs!!
Object object = clazz.newInstance();
model.addAttribute("object", object);
return "create";
}
#RequestMapping(value="create", method=RequestMethod.POST)
public #ResponseBody Object POST(#ModelAttribute(value="object") Object object)
{
System.out.println("POST! got type: " + object.getClass().getName());
return object;
}
In the Post Method I get NULL for #ModelAttribute(value="object") Object object
If I change it to #ModelAttribute(value="object") realType object it is working perfectly fine. But I don't know the type yet.
I thought the #ModelAttribute can achieve this anyway with the name "object" but apparently not. What am I missing?
There is no actual model object named object when you submit, spring constructs it based on the parameter type and will bind the properties accordingly.
You have 2 choices to make it work
Store the object in the session
Use a #ModelAttribute annotated method
If neither of these are there spring will simply look at the method argument and use reflection to construct an instance of that class. So in your case it will only be Object and after that binding will fail.
Store object in the session
#Controller
#SessionAttributes("object")
public class MyController { ... }
Make sure that when you are finished that you call the setComplete() method on a SessionStatus object.
Use a #ModelAttribute annotated method
Instead of creating and adding the object in a request handling method create a speficic method for it.
#ModelAttribute("object")
public Object formBackingObject() {
Class<?> clazz = ????; // a Random POJO is chosen, i want to use POJOs!!
Object object = clazz.newInstance();
return object;
}
This method will be called before each request handling method, so that a newly fresh object is constructed which will be used for binding.

How do you handle deserializing empty string into an Enum?

I am trying to submit a form from Ext JS 4 to a Spring 3 Controller using JSON. I am using Jackson 1.9.8 for the serialization/deserialization using Spring's built-in Jackson JSON support.
I have a status field that is initially null in the Domain object for a new record. When the form is submitted it generates the following json (scaled down to a few fields)
{"id":0,"name":"someName","status":""}
After submitted the following is seen in the server log
"nested exception is org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.blah.domain.StatusEnum from String value '': value not one of the declared Enum instance names"
So it appears that Jackson is expecting a valid Enum value or no value at all including an empty string. How do I fix this whether it is in Ext JS, Jackson or Spring?
I tried to create my own ObjectMapper such as
public class MyObjectMapper extends Object Mapper {
public MyObjectMapper() {
configure(DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
}
}
and send this as a property to MappingJacksonMappingView but this didn't work. I also tried sending it in to MappingJacksonHttpMessageConverter but that didn't work. Side question: Which one should I be sending in my own ObjectMapper?
Suggestions?
The other thing you could do is create a specialized deserializer (extends org.codehaus.jackson.map.JsonDeserializer) for your particular enum, that has default values for things that don't match. What I've done is to create an abstract deserializer for enums that takes the class it deserializes, and it speeds this process along when I run into the issue.
public abstract class EnumDeserializer<T extends Enum<T>> extends JsonDeserializer<T> {
private Class<T> enumClass;
public EnumDeserializer(final Class<T> iEnumClass) {
super();
enumClass = iEnumClass;
}
#Override
public T deserialize(final JsonParser jp,
final DeserializationContext ctxt) throws IOException, JsonProcessingException {
final String value = jp.getText();
for (final T enumValue : enumClass.getEnumConstants()) {
if (enumValue.name().equals(value)) {
return enumValue;
}
}
return null;
}
}
That's the generic class, basically just takes an enum class, iterates over the values of the enum and checks the next token to match any name. If they do it returns it otherwise return null;
Then If you have an enum MyEnum you'd make a subclass of EnumDeserializer like this:
public class MyEnumDeserializer extends EnumDeserializer<MyEnum> {
public MyEnumDeserializer() {
super(MyEnum.class);
}
}
Then wherever you declare MyEnum:
#JsonDeserialize(using = MyEnumDeserializer.class)
public enum MyEnum {
...
}
I'm not familiar with Spring, but just in case, it may be easier to handle that on the client side:
Ext.define('My.form.Field', {
extend: 'Ext.form.field.Text',
getSubmitValue: function() {
var me = this,
value;
value = me.getRawValue();
if ( value === '' ) {
return ...;
}
}
});
You can also disallow submitting empty fields by setting their allowBlank property to false.
Ended up adding defaults in the EXT JS Model so there is always a value. Was hoping that I didn't have to this but it's not that big of a deal.
I have the same issue. I am reading a JSON stream with some empty strings. I am not in control of the JSON stream, because it is from a foreign service. And I am always getting the same error message. I tried this here:
mapper.getDeserializationConfig().with(DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
But without any effect. Looks like a Bug.

databinding,validate,exception in spring mvc3

I am using the spring mvc3,and I found that I am confused with the some concepts,so I make a summary, and post it here.
Data binding.
I use struct2 before where if I have a bean in the action(i..e,named 'Person'),then when the following url is requested:
http://localhost:8080/app/form?person.id=1&person.name=xxx&pet.name=yy
Then a new instance of Person will be created and the parameters '1' and 'xxx' will be populated to this instance.
And a new instance of Pet will be created,and the name 'yy' will be populated to this bean.
This is the only way for data binding in struct2:
You specify the beanname.property in your request.
Now in spring mvc3,I know one way to binding the data:
http://localhost:8080/app/form?id=1&name=xxx&other=yy
#RequestMapping('form')
public String form(Person person,BindingResult result){
//now I get the person
}
Even it work,but I have some questions:
1) I have three parameters in the request url "name",'pass','other',how does spring know which parameters should be populated to my bean(model).
2) how about if I want to bind parameters to more than one model like the example in struct2(both person and pet)?
Furthermore,what does the modelAttribute and commandName attribute in the spring tag "form" mean?
2. Validate
For bean(ignore the getter and setter in the example):
import javax.validation.constraints.NotNull;
public class Bean {
#NotNull(message="id can not be null")
private int id;
}
I use this controller:
#RequestMapping("val")
public #ResponseBody
String validate(#Valid Bean bean, BindingResult result) {
if (result.hasErrors()) {
return result.getAllErrors() + "";
} else
return "no error";
}
I found that only the 'NotEmpty' works.
Since if I use this url:
/val?name=xxx ==> no error !! // id is null now,why it does not has error?
3. The type conversion.
Take this url for example:
http://localhost:8080/app/form?id=1&name=xxx&other=yy
Obviously it will throw 'NumberFormatException' if I set the id to string value.
Then where to catch this exception? If in the controller,then I have to write so many try-catch block in each controller.
Furthermore,the the type conversion exception do not limited to only 'NumberFormatException',it may be 'dataformaterrorexception' and etc.
But they all belongs to the type conversion,how to handle the using a common solution?

Resources