Explication about Spring Converter with Spring MVC - I can't understand - spring

I'd like someone could explication about converter in spring mvc.
My domain class:
#Entity
#Table(name = "TIME_SHEET")
public class TimeSheet implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID_TIME_SHEET")
private Long id;
#NotNull(message = "timesheet.cadastro.horainicio.obrigatorio")
#Temporal(TemporalType.TIME)
#Column(name = "INICIO", nullable = false)
private Date horaInicio;
#NotNull(message = "timesheet.cadastro.horafim.obrigatorio")
#Temporal(TemporalType.TIME)
#Column(name = "FIM", nullable = false)
private Date horaFim;
#Column(name = "LATITUDE", nullable = true)
private Double latitude;
#Column(name = "LONGITUDE", nullable = true)
private Double longitude;
#Size(max = 300,message = "timesheet.cadastro.observacao.acimaDoPermitido")
#Column(name = "OBSERVACAO", nullable = true)
private String observacao;
//#NotNull(message = "timesheet.cadastro.dia.obrigatorio")
#ManyToOne(cascade = javax.persistence.CascadeType.ALL)
#JoinColumn(name = "ID_DIAS")
private Dias dia;
//#NotNull(message = "timesheet.cadastro.usuario.obrigatorio")
#ManyToOne(cascade = javax.persistence.CascadeType.ALL)
#JoinColumn(name = "ID_USUARIO")
private Usuario usuario;
...
My class converter:
public class IdToUsuarioConverter implements Converter<String, Usuario> {
#Autowired
private IusuarioService usuarioService;
public Usuario convert(String id) {
return usuarioService.buscaPorId(Long.valueOf(id));
}
}
In my springmvc.xml:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="br.com.infowhere.timeSheet.converter.IdToUsuarioConverter"/>
</set>
</property>
</bean>
I don't have problem, but my question is:
1-) When my converter will act ?
2-) My .jsp will post a form where I have one list similar:
<form:select path="user" items="${userList}" multiple="false" />
HTML:
<select id="user" name="user">
<option value="1">User 1</option>
<option value="2">User 2</option>
</select>
At what time my converter will work ?
I'm sorry but I'm trying to understand about converter.
thanks !!!

Your converter will convert id's to Usario objects in your controllers.
For example:
#Controller
public class MyController {
#RequestMapping("/showUsario")
public String showUsario(#RequestParam("id") Usario usario, Model model) {
model.addAttribute("usario", usario);
return "showUsario";
}
}
Then a request to /showUsario?id=123 will convert String "123" to Usario using the converter. If you didn't have a converter you would have to put String id (instead of Usario) in method parameters and manually convert the id to Usario. This way, Spring does it for you using your converter.

Related

Spring MVC Error: Failed to convert property value of type java.lang.String to required type

I can't let this exception go:
Failed to convert property value of type java.lang.String to required type com.company.springdemo.entity.Product for property productId; nested exception is java.lang.IllegalStateException: Cannot convert value of type java.lang.String to required type com.company.springdemo.entity.Product for property productId: no matching editors or conversion strategy found
Order Model
#Entity
#Table(name = "orders") // naming the table only order, will throw exception
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "order_id")
private Integer orderId;
#OneToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
#JoinColumn(name = "product_id")
private Product productId;
#ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
#JoinColumn(name = "client_id")
private Client client;
....
Product Model
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "product_id")
private Integer id;
#Column(name = "product_name")
private String productName;
#Column(name = "product_serial")
private String productSerial;
...
Client Model
#Entity
#Table(name = "clients")
public class Client {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotEmpty
#Column(name = "first_name")
private String firstName;
#NotEmpty
#Column(name = "last_name")
private String lastName;
#NotEmpty
#Email
#Column(name = "email")
private String email;
#NotEmpty
#Column(name = "location")
private String location;
#OneToMany(mappedBy = "client",cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Order> orders;
Controller, where I save the order with related client and product
#PostMapping("add")
public ModelAndView addOrder( #Validated #ModelAttribute("ords") Order order, BindingResult bindingResult ){
if (bindingResult.hasErrors()) {
System.out.println("Having errors: " + bindingResult.getAllErrors());
Iterable<Product> products = productService.listProducts();
Iterable<Client> clients = clientService.listClients();
System.out.println("Error "+ bindingResult.getAllErrors());
ModelAndView mv = new ModelAndView("orders/add-order");
mv.addObject("products",products);
mv.addObject("clients",clients);
return mv;
}
try {
orderService.saveOrder(order);
} catch (Exception e) {
e.printStackTrace();
}
ModelAndView mv = new ModelAndView("redirect:list");
return mv;
}
Finally, my JSP form View page
<form:form action="add" method="post" modelAttribute="ords">
<label for="productId" >Product Id</label>
<form:select path="productId" >
<c:forEach var="product" items="${products}">
<form:option value="${product.id}">${product.productName}</form:option>
</c:forEach>
</form:select>
<form:errors path="productId"/>
<br>
<label for="client" >Client Id</label>
<form:select path="client" >
<c:forEach var="client" items="${clients}">
<form:option value="${client.id}">${client.id} - ${client.lastName}</form:option>
</c:forEach>
</form:select>
<form:errors path="client"/>
<br>
<input type="submit" value="Place Order">
</form:form>
What am I doing wrong?
You most likely need to build a converter class such as this one :
#Component("facilityConverter")
public class FacilityConverter implements Converter<String, Facility>
{
#Autowired
FacilityService facilityService;
#Override
public Facility convert(String id)
{
return facilityService.findById(Integer.parseInt(id));
}
}
Then, you need to register it by implementing the addFormatters method inside of a configuration class implementing WebMvcConfigurer like so :
#Override
public void addFormatters (FormatterRegistry registry)
{
registry.addConverter((FacilityConverter)ctx.getBean("facilityConverter"));
}
Your entities will then correctly be mapped from a dropdown selection. Also, this might not be part of your issue but you can just build your dropdowns like this :
<form:select name="linkedInterface" path="linkedInterface" id="linkedInterface">
<form:options items="${interfaces}" itemLabel="name" itemValue="id"/>
</form:select>
The productId field is actually a Product object, not an ID (String/int). You need your JSP to use path="productId.id" rather than path="productId".
(Although I'd also suggest you also rename the field product rather than productId.)
<form:select path="product.id">
I think you'll hit the same issue on your <form:select path="client"> too.

Spring 4 MVC Form: Create Object with list of sub objects

I looking for help in understanding how to create a new object through a form which has the user select multiple sub-objects (which will come pre-populated) and available to select with a checkbox.
OrderController.java
#RequestMapping(value = { "/order" }, method = RequestMethod.GET)
public String order(ModelMap model) {
List<Exam> exams = examService.findAllExams();
List<Document> documents = documentService.findAllDocuments();
model.addAttribute("exams", exams);
model.addAttribute("documents", documents);
return "order"; // jsp page reference
}
Order.java
#Entity
#Table(name="\"order\"")
public class Order implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "order_id", unique = true, nullable = false)
private Integer id;
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "uuid", unique = true, nullable = false)
private String uuid;
#Temporal(TemporalType.DATE)
#Column(name = "order_date", unique = true, nullable = false)
private Date orderDate;
#Column(name="order_status", nullable=false)
private String orderStatus;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
private User user;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "order")
private Set<OrderExam> orderExams = new HashSet<OrderExam>(0);
#OneToMany(fetch = FetchType.LAZY, mappedBy = "order")
private Set<OrderDocument> orderDocuments = new HashSet<OrderDocument(0);
//getters & setters
}
OrderExam.java
#Entity
#Table(name="order_exam")
public class OrderExam implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "order_exam_id", unique = true, nullable = false)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id", nullable = false)
private Order order;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "exam_id", nullable = false)
private Exam exam;
#Column(name="exam_amount", nullable=true)
private Integer examAmount;
#Column(name="answer_sheet_amount", nullable=true)
private String answerSheetName;
#Column(name="students_per_csv", nullable=true)
private String studentsPerCSV;
#Column(name="pas", nullable=true)
private Boolean pearsonAnswerSheet;
//getters & setters
}
Exam.java
#Entity
#Table(name="exam")
public class Exam implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "exam_id", unique = true, nullable = false)
private Integer id;
#NotEmpty
#Column(name="name", unique=true, nullable=false)
private String name;
#NotEmpty
#Column(name="code", unique=true, nullable=false)
private String code;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "exam")
private Set<OrderExam> exams = new HashSet<OrderExam>(0);
//getters & setters
}
As you can see I am passing in a list of exams and documents which will populate a form with available options (can be seen in the image below (exams anyway)). The user needs to be able to select multiple rows, so that a single order has multiple exams and documents associated to it.
My order.jsp is a little much to post the entire thing here but here is the part I have which is displayed in the image above.
Order.jsp
<form:form method="POST" modelAttribute="order" class="form-horizontal form-label-left">
<c:forEach items="${exams}" var="exam">
<tr>
<th scope="row"><input type="checkbox" class="flat"></th>
<td><input id="middle-name" type="text" name="middle-name" readonly="readonly" value="${exam.name} - ${exam.code}" class="form-control col-md-7 col-xs-12"></td>
<td><input id="middle-name" type="text" name="middle-name" value="0" class="form-control col-md-3 col-xs-12"></td>
<td><input id="middle-name" type="text" name="middle-name" value="0" class="form-control col-md-3 col-xs-12"></td>
<td><input id="middle-name" type="text" name="middle-name" value="0" class="form-control col-md-3 col-xs-12"></td>
<c:choose>
<c:when test="${exam.name == 'Algebra 2 (Common Core)'}">
<th scope="row"><input type="checkbox" class="flat"></th>
</c:when>
<c:otherwise>
<th scope="row"></th>
</c:otherwise>
</c:choose>
</tr>
</c:forEach>
<!-- Other Stuff Goes Here -->
</form:form>
So in short, would someone be willing to show me how to set up the form in the way I described above? Thanks in advance.
Your question is a bit broad however you could try this as below. I have only covered exams. Principal for documents will be the same.
You will need a couple of new classes to capture the submitted form inputs:
Order Form to Capture Selections
public class OrderForm{
private List<ExamWrapper> allAvailableExams = new ArrayList<>();
private XOptionPrintWrapper selectedWrapper;
public OrderForm(){
}
//getters and setters
}
Exam Wrapper : Decorates an Exam with a 'selected' property
public class ExamWrapper{
private boolean selected;
private Exam exam;
public ExamWrapper(Exam exam){
this.exam = exams;
}
//getters and setters
}
Change Contoller to
public class OrderController{
//Exams model populated by the method below
//moved as we also need it populated on POST
#RequestMapping(value = { "/order" }, method = RequestMethod.GET)
public String order(ModelMap modelMap) {
//only needed on GET so put in model here
List<XOptionPrintWrapper> availableWrappers = //someList;
modelMap.put("availableWrappers", availableWrappers);
return "order";
}
//handles for submit
//model atribute is automatically populated by the framework
#RequestMapping(value = { "/order" }, method = RequestMethod.POST)
public String order(#ModelAttribute("orderForm") OrderForm orderForm) {
//process selected exams
return "nextView";
}
//on get populates the initial model for display
//on post create an instance which the form params will be bound to
#ModelAttribute("orderForm")
public OrderForm getOrderForm(){
OrderForm orderForm = new OrderForm();
List<Exam> exams = examService.findAllExams();
for(Exam exam : exams){
orderForm.getAllAvailableExams.add(new ExamWrapper(exam));
}
return orderForm;
}
}
In JSP use Sping support for binding to indexed properties:
<form:form method="POST" modelAttribute="orderForm" class="form-horizontal form-label-left">
<c:forEach items="${orderForm.allAvailableExams}" var="exam" varStatus="status">
<tr>
<th scope="row"><input name="allAvailableExams[${status.index}].selected"
type="checkbox" class="flat"></th>
</tr>
</c:forEach>
<form:select path="selectedWrapper">
<form:options items="${availableWrappers}"
itemValue="somePropertyOfXOptionPrintWrapper "
itemLabel="somePropertyOfXOptionPrintWrapper " />
</form:select>
</form>
I obviously haven't been able to try all of this but think it should all be okay.

Test Controllers with Mocks when using Spring-data converters

I want to test my BookFormController where I have addBook forms. I want to Mock every service which I use and everything seems to works fine but the problem is that my POST method is based on spring-data converters to make Author object and Type objects from their ids.
Now I think I would like to mock in some way those converters so when I pass author="1" it should convert book author to some object so my NotNull and NotEmpty validation on author and types passed.
Book.class:
public class Book extends Item {
#ManyToOne
#JoinColumn(name = "author_id")
#NotNull
private Author author;
Items.class
#NotEmpty
#Column(nullable = false)
private String isbn;
#NotEmpty
#Column(nullable = false)
private String title;
#Column(name = "page_number", nullable = false)
#Min(1)
#NotNull
private Integer pageNumber;
#DateTimeFormat(iso = ISO.DATE)
#Column(name = "release_date", nullable = false)
#NotNull
private LocalDate releaseDate;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "items_types", joinColumns = {
#JoinColumn(name = "item_id", referencedColumnName = "id") }, inverseJoinColumns = {
#JoinColumn(name = "type_id", referencedColumnName = "id") })
#NotEmpty
private Set<Type> types = new HashSet<>();
#OneToMany(mappedBy = "item", cascade = { CascadeType.REMOVE })
private List<Borrow> borrows;
BookFormController POST method:
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addBookAction(#Valid #ModelAttribute("book") Book book, BindingResult result, Model model,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "book/bookForm";
}
bookService.save(book);
redirectAttributes.addFlashAttribute("messageCode", "BookAdd.message.successfull");
return "redirect:/books";
}
And my tests:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { WebConfig.class })
#WebAppConfiguration
public class BookFormControllerTest {
private MockMvc mockMvc;
#Mock
private BookService bookService;
#Mock
private TypeService typeService;
#Mock
private AuthorService authorService;
#InjectMocks
private BookFormController bookFormController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(bookFormController).build();
}
#Test
public void testAddBookPost() throws Exception {
Mockito.doNothing().when(bookService).save(any(Book.class));
mockMvc.perform(post("/books/add")
.param("title", "Spring MVC")
.param("isbn", "123QWE")
.param("author", "1")
.param("releaseDate", "2010-10-10")
.param("pageNumber", "256")
.param("types", "1")
.param("types", "2"))
.andExpect(status().is3xxRedirection())
.andExpect(flash().attribute("messageCode", "BookAdd.message.successfull"))
.andExpect(redirectedUrl("/books"));
}
And this test doesn't work as it should because of converters. When I remove NotNull and NotEmpty from book/items objects and don't send those values in POST, this test works. So what should I do?

Spring 4 ZoneDateTime Restful recursive output

I am new on Java 8 and Spring 4
i have tried to implement spring boot with module (Spring boot web, Spring boot jpa)
i have tried to implement JpaAuditing on my entity with the following code:
//AbstractAuditedEntity.class
#MappedSuperclass
public class AbstractAuditedEntity {
#CreatedBy
#Column(name = "CREATED_BY")
private String createdBy;
// #Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")
#CreatedDate
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
#Column(name = "CREATED_DATE")
// #Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private ZonedDateTime createdDate;
#LastModifiedBy
#Column(name = "LAST_MODIFIED_BY")
private String lastModifiedBy;
// #Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
#LastModifiedDate
#Column(name = "LAST_MODIFIED_DATE")
// #Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
private ZonedDateTime lastModifiedDate;
/*setter getter are omitted*/
}
and the User entity with the following code :
#Entity
#Table(name = "common_user")
public class User extends AbstractAuditedEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
/*other fields are omitted*/
}
and my controller :
#RestController
public class UserCtrl {
#Autowired
UserRepository userRepository;
#RequestMapping(value = "/user", method = RequestMethod.GET)
#ResponseBody
public User index() {
User one = userRepository.findOne(1L);
return one;
}
}
the result is of field createdDate and lastModifiedDate are recursive :(
{"createdBy":"SYSTEM","createdDate":{"offset":{"totalSeconds":25200,"rules": {"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:00"},"zone":{"id":"Asia/Jakarta","rules":{"fixedOffset":false,"transitionRules":[],"transitions":[{"offsetBefore":{"totalSeconds":25632,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:07:12"},"offsetAfter":{"totalSeconds":26400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:20"},"dateTimeAfter":{"hour":0,"minute":0,"nano":0,"second":0,"month":"JANUARY","year":1924,"dayOfMonth":1,"dayOfWeek":"TUESDAY","dayOfYear":1,"monthValue":1,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":768,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":23,"minute":47,"nano":0,"second":12,"month":"DECEMBER","year":1923,"dayOfMonth":31,"dayOfWeek":"MONDAY","dayOfYear":365,"monthValue":12,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-1451719200,"nano":0}},{"offsetBefore":{"totalSeconds":26400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:20"},"offsetAfter":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"dateTimeAfter":{"hour":0,"minute":10,"nano":0,"second":0,"month":"NOVEMBER","year":1932,"dayOfMonth":1,"dayOfWeek":"TUESDAY","dayOfYear":306,"monthValue":11,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":600,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"NOVEMBER","year":1932,"dayOfMonth":1,"dayOfWeek":"TUESDAY","dayOfYear":306,"monthValue":11,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-1172906400,"nano":0}},{"offsetBefore":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"offsetAfter":{"totalSeconds":32400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+09:00"},"dateTimeAfter":{"hour":1,"minute":30,"nano":0,"second":0,"month":"MARCH","year":1942,"dayOfMonth":23,"dayOfWeek":"MONDAY","dayOfYear":82,"monthValue":3,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":5400,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"MARCH","year":1942,"dayOfMonth":23,"dayOfWeek":"MONDAY","dayOfYear":82,"monthValue":3,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-876641400,"nano":0}},{"offsetBefore":{"totalSeconds":32400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+09:00"},"offsetAfter":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"dateTimeAfter":{"hour":22,"minute":30,"nano":0,"second":0,"month":"SEPTEMBER","year":1945,"dayOfMonth":22,"dayOfWeek":"SATURDAY","dayOfYear":265,"monthValue":9,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":-5400,"zero":false,"negative":true,"nano":0,"units":["SECONDS","NANOS"]},"gap":false,"overlap":true,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"SEPTEMBER","year":1945,"dayOfMonth":23,"dayOfWeek":"SUNDAY","dayOfYear":266,"monthValue":9,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-766054800,"nano":0}},{"offsetBefore":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"offsetAfter":{"totalSeconds":28800,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+08:00"},"dateTimeAfter":{"hour":0,"minute":30,"nano":0,"second":0,"month":"MAY","year":1948,"dayOfMonth":1,"dayOfWeek":"SATURDAY","dayOfYear":122,"monthValue":5,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":1800,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"MAY","year":1948,"dayOfMonth":1,"dayOfWeek":"SATURDAY","dayOfYear":122,"monthValue":5,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-683883000,"nano":0}},{"offsetBefore":{"totalSeconds":28800,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+08:00"},"offsetAfter":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"dateTimeAfter":{"hour":23,"minute":30,"nano":0,"second":0,"month":"APRIL","year":1950,"dayOfMonth":30,"dayOfWeek":"SUNDAY","dayOfYear":120,"monthValue":4,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":-1800,"zero":false,"negative":true,"nano":0,"units":["SECONDS","NANOS"]},"gap":false,"overlap":true,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"MAY","year":1950,"dayOfMonth":1,"dayOfWeek":"MONDAY","dayOfYear":121,"monthValue":5,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-620812800,"nano":0}},{"offsetBefore":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"offsetAfter":{"totalSeconds":25200,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:00"},"dateTimeAfter":{"hour":23,"minute":30,"nano":0,"second":0,"month":"DECEMBER","year":1963,"dayOfMonth":31,"dayOfWeek":"TUESDAY","dayOfYear":365,"monthValue":12,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":-1800,"zero":false,"negative":true,"nano":0,"units":["SECONDS","NANOS"]},"gap":false,"overlap":true,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"JANUARY","year":1964,"dayOfMonth":1,"dayOfWeek":"WEDNESDAY","dayOfYear":1,"monthValue":1,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-189415800,"nano":0}}]}},"hour":15,"minute":37,"nano":576000000,"second":41,"month":"AUGUST","year":2014,"dayOfMonth":21,"dayOfWeek":"THURSDAY","dayOfYear":233,"monthValue":8,"chronology":{"calendarType":"iso8601","id":"ISO"}},"lastModifiedBy":"SYSTEM","lastModifiedDate":{"offset":{"totalSeconds":25200,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:00"},"zone":{"id":"Asia/Jakarta","rules":{"fixedOffset":false,"transitionRules":[],"transitions":[{"offsetBefore":{"totalSeconds":25632,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:07:12"},"offsetAfter":{"totalSeconds":26400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:20"},"dateTimeAfter":{"hour":0,"minute":0,"nano":0,"second":0,"month":"JANUARY","year":1924,"dayOfMonth":1,"dayOfWeek":"TUESDAY","dayOfYear":1,"monthValue":1,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":768,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":23,"minute":47,"nano":0,"second":12,"month":"DECEMBER","year":1923,"dayOfMonth":31,"dayOfWeek":"MONDAY","dayOfYear":365,"monthValue":12,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-1451719200,"nano":0}},{"offsetBefore":{"totalSeconds":26400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:20"},"offsetAfter":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"dateTimeAfter":{"hour":0,"minute":10,"nano":0,"second":0,"month":"NOVEMBER","year":1932,"dayOfMonth":1,"dayOfWeek":"TUESDAY","dayOfYear":306,"monthValue":11,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":600,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"NOVEMBER","year":1932,"dayOfMonth":1,"dayOfWeek":"TUESDAY","dayOfYear":306,"monthValue":11,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-1172906400,"nano":0}},{"offsetBefore":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"offsetAfter":{"totalSeconds":32400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+09:00"},"dateTimeAfter":{"hour":1,"minute":30,"nano":0,"second":0,"month":"MARCH","year":1942,"dayOfMonth":23,"dayOfWeek":"MONDAY","dayOfYear":82,"monthValue":3,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":5400,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"MARCH","year":1942,"dayOfMonth":23,"dayOfWeek":"MONDAY","dayOfYear":82,"monthValue":3,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-876641400,"nano":0}},{"offsetBefore":{"totalSeconds":32400,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+09:00"},"offsetAfter":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"dateTimeAfter":{"hour":22,"minute":30,"nano":0,"second":0,"month":"SEPTEMBER","year":1945,"dayOfMonth":22,"dayOfWeek":"SATURDAY","dayOfYear":265,"monthValue":9,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":-5400,"zero":false,"negative":true,"nano":0,"units":["SECONDS","NANOS"]},"gap":false,"overlap":true,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"SEPTEMBER","year":1945,"dayOfMonth":23,"dayOfWeek":"SUNDAY","dayOfYear":266,"monthValue":9,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-766054800,"nano":0}},{"offsetBefore":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"offsetAfter":{"totalSeconds":28800,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+08:00"},"dateTimeAfter":{"hour":0,"minute":30,"nano":0,"second":0,"month":"MAY","year":1948,"dayOfMonth":1,"dayOfWeek":"SATURDAY","dayOfYear":122,"monthValue":5,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":1800,"zero":false,"negative":false,"nano":0,"units":["SECONDS","NANOS"]},"gap":true,"overlap":false,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"MAY","year":1948,"dayOfMonth":1,"dayOfWeek":"SATURDAY","dayOfYear":122,"monthValue":5,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-683883000,"nano":0}},{"offsetBefore":{"totalSeconds":28800,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+08:00"},"offsetAfter":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"dateTimeAfter":{"hour":23,"minute":30,"nano":0,"second":0,"month":"APRIL","year":1950,"dayOfMonth":30,"dayOfWeek":"SUNDAY","dayOfYear":120,"monthValue":4,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":-1800,"zero":false,"negative":true,"nano":0,"units":["SECONDS","NANOS"]},"gap":false,"overlap":true,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"MAY","year":1950,"dayOfMonth":1,"dayOfWeek":"MONDAY","dayOfYear":121,"monthValue":5,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-620812800,"nano":0}},{"offsetBefore":{"totalSeconds":27000,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:30"},"offsetAfter":{"totalSeconds":25200,"rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]},"id":"+07:00"},"dateTimeAfter":{"hour":23,"minute":30,"nano":0,"second":0,"month":"DECEMBER","year":1963,"dayOfMonth":31,"dayOfWeek":"TUESDAY","dayOfYear":365,"monthValue":12,"chronology":{"calendarType":"iso8601","id":"ISO"}},"duration":{"seconds":-1800,"zero":false,"negative":true,"nano":0,"units":["SECONDS","NANOS"]},"gap":false,"overlap":true,"dateTimeBefore":{"hour":0,"minute":0,"nano":0,"second":0,"month":"JANUARY","year":1964,"dayOfMonth":1,"dayOfWeek":"WEDNESDAY","dayOfYear":1,"monthValue":1,"chronology":{"calendarType":"iso8601","id":"ISO"}},"instant":{"epochSecond":-189415800,"nano":0}}]}},"hour":15,"minute":37,"nano":576000000,"second":41,"month":"AUGUST","year":2014,"dayOfMonth":21,"dayOfWeek":"THURSDAY","dayOfYear":233,"monthValue":8,"chronology":{"calendarType":"iso8601","id":"ISO"}},"id":1,"firstName":"adil","lastName":"ramdan","username":"admin","password":null,"email":"adil.ramdan#gmail.com","photo":"pp.jpg","group":null,"shaPassword":null,"authToken":null}
How to format ZoneDateTime in the Restful ?thanks before
That's not actually recursive; you can see for yourself by posting that json string into http://jsonformatter.curiousconcept.com/.
If you want to use ZonedDateTime and you don't want all of its properties converted to JSON, you might add #JsonIgnore to the field and then adding getters for each field that you want. For example:
#JsonIgnore
#CreatedDate
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
#Column(name = "CREATED_DATE")
private ZonedDateTime createdDate;
public Month getMonthCreated(){
return createdDate.getMonth();
}

Invalid property of bean class Bean property is not readable or has an invalid getter method

Im new with Spring, and Iam having this exception.
I have a jsp, with many selects. All of them work fine, but one show this exception:
org.apache.jasper.JasperException: Ha sucedido una excepción al procesar la página JSP /WEB-INF/pages/nuevo-expediente.jsp en línea 45
42: <td>
43: <form:select path="expedientePadre.codExpediente">
44: <form:option value="-" label="Seleccione un expediente"/>
45: <form:options items="${expedientes}" itemLabel="codExpediente" itemValue="codExpediente"/>
46: </form:select>
47: <form:errors path="expedientePadre" element="span"/>
48: </td>
org.springframework.beans.NotReadablePropertyException: Invalid property 'codExpediente' of bean class [com.atlantis.atecliente.model.TipoExpediente]: Bean property 'codExpediente' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
Im implementing the selct same way others which are working fine. Here the jsp code:
<tr>
<td>Expediente padre:</td>
<td>
<form:select path="expedientePadre.codExpediente">
<form:option value="-" label="Seleccione un expediente"/>
<form:options items="${expedientes}" itemLabel="codExpediente" itemValue="codExpediente"/>
</form:select>
<form:errors path="expedientePadre" element="span"/>
</td>
</tr>
Here the controller:
#RequestMapping(value = "nuevo-expediente")
public String createExpedienteGet(Model model) {
model.addAttribute("expediente", new Expediente());
model.addAttribute("expedienteP", new Expediente());
List<TipoResolucion> resoluciones = service.getResoluciones();
List<TipoExpediente> listaTipos = service.getTipos();
List<EstadoExpediente> listaEstados = service.getEstados();
List<Expediente> listaExpedientes = service.getExpedientes();
List<TipoRelacion> listaRelaciones = service.getRelaciones();
List<CanalExpediente> listaCanales = service.getCanales();
List<IdiomaExpediente> listaIdiomas = service.getIdiomas();
model.addAttribute("resoluciones", resoluciones);
model.addAttribute("tipos", listaTipos);
model.addAttribute("estados", listaEstados);
model.addAttribute("expedientes", listaExpedientes);
model.addAttribute("tiposRelacion", listaRelaciones);
model.addAttribute("canales", listaCanales);
model.addAttribute("idiomas", listaIdiomas);
return "nuevo-expediente";
}
#RequestMapping(value = "nuevo-expediente", method = RequestMethod.POST)
public String createExpedientePost(#ModelAttribute("expediente") Expediente expediente, BindingResult result) {
service.createExpediente(expediente);
return "redirect:expedientes";
}
here, the entity Expediente:
#Entity
#Table(name="Expediente")
public class Expediente implements Serializable {
#Id
#Column(length = 15)
private String codExpediente;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "tipoExpediente")
private TipoExpediente tipoExpediente;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "estadoExpediente")
private EstadoExpediente estadoExpediente;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "expedientePadre")
private Expediente expedientePadre;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "tipoRelacion")
private TipoRelacion tipoRelacion;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "canalEntrada")
private CanalExpediente canalEntrada;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "idiomaEntrada")
private IdiomaExpediente idiomaEntrada;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "idiomaSalida")
private IdiomaExpediente idiomaSalida;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "tipoResolucion")
private TipoResolucion tipoResolucion;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "canalSalida")
private CanalExpediente canalSalida;
#Column(length = 10)
private String numeroSerie;
#Column(length = 10)
private String numeroHoja;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date fechaRedaccion;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date fechaRecepcion;
#Column(length = 200)
private String asunto;
#Column (length = 1000)
private String descripcion;
#Column(length = 20)
private String usuarioRegistro;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date fechaRegistro;
#Column (length = 20)
private String usuarioModificacion;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date fechaModificacion;
#Column (length = 20)
private String usuarioCierre;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date fechaCierre;
public String getCodExpediente() {
return codExpediente;
}
public void setCodExpediente(String codExpediente) {
this.codExpediente = codExpediente;
}
............................
............................
And finally the TipoExpediente Entity
package com.atlantis.atecliente.model;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#Table
public class TipoExpediente implements Serializable {
#Id
#Column(length = 40)
private String tipo;
public String getTipo() {
return tipo;
}
public void setTipo(String tipo) {
this.tipo = tipo;
}
}
I think it could happen because the expedientePadre property, is a foreign key to the same entity Expediente, but I dont know resolve it...
Some help? Thanks!
I think the problem is that your class TipExpediente class does not have getter or setter methods for the property codExpedient. Spring is looking at your TipoExpediente class and expecting it to have the property you outlined in the JSP.

Resources