Spring MVC 3: return a Spring-Data Page as JSON - issue with PagedResourcesAssembler -


so, i'm new spring , java in general

what try have on same rendered view form post data filter result list displayed under form.

i have simple domain class follows:

@entity @table(name = "sec_person") public class person {  @id @generatedvalue(strategy = generationtype.sequence, generator = "seq_sec_person") @sequencegenerator(name = "seq_sec_person", sequencename = "seq_sec_person") @column(name = "id") private long id;  @column(name = "code", nullable = false) private string code;  @column(name = "firstname", nullable = false) private string firstname;  @column(name = "surname", nullable = false) private string surname;  @column(name = "creationdate") private datetime creationdate;  //getters , setters 

a dto because want domain decoupled presentation

public class persondto { private long id;  @notempty private string code;  @notempty private string firstname;  @notempty private string surname;  private datetime creationdate;  public persondto() { } //getters , setters 

a repository extending jpa , querydsl

public interface personrepository extends jparepository<person, long>, querydslpredicateexecutor<person> {} 

a data access class search null safe (thanks guava) , equivalent not null safe

the person criteria:

public class personcriteria {  private string code; private string surname; private string firstname; private localdate creationdatefrom; private localdate creationdateto;  //getters , setters } 

the null safe version

public class nullsafepersoncriteria {  private final personcriteria personcriteria;  public nullsafepersoncriteria(final personcriteria personcriteria) {     checkargument(personcriteria != null);     this.personcriteria = personcriteria; }  public optional<string> getcode() {     return optional.fromnullable(this.personcriteria.getcode()); }  public optional<string> getsurname() {     return optional.fromnullable(this.personcriteria.getsurname()); }  public optional<string> getfirstname() {     return optional.fromnullable(this.personcriteria.getfirstname()); }  public optional<localdate> getcreationdatefrom() {     return optional.fromnullable(this.personcriteria.getcreationdatefrom()); }  public optional<localdate> getcreationdateto() {     return optional.fromnullable(this.personcriteria.getcreationdateto()); } 

my predicate search

public class personpredicates { public static predicate personlitstquery(final personcriteria personcriteria) {     final qperson person = qperson.person;     final nullsafepersoncriteria nspersoncriteria = new nullsafepersoncriteria(personcriteria);      booleanexpression criteria = qperson.person.isnotnull();     if (nspersoncriteria.getcode().ispresent()) {         criteria = criteria.and(person.code.matches(nspersoncriteria.getcode().get()));     }      if (nspersoncriteria.getsurname().ispresent()) {         criteria.and(person.surname.startswithignorecase(nspersoncriteria.getsurname().get()));     }      if (nspersoncriteria.getfirstname().ispresent()) {         criteria.and(person.firstname.startswithignorecase(nspersoncriteria.getfirstname().get()));     }      if ((nspersoncriteria.getcreationdatefrom().ispresent()) && (nspersoncriteria.getcreationdateto().ispresent())) {         criteria.and(person.creationdate.between(nspersoncriteria.getcreationdatefrom().get().todatetimeatstartofday(),                 nspersoncriteria.getcreationdateto().get().todatetimeatstartofday()));     }      return criteria; } 

my service implementation follows:

@service public class personserviceimpl implements personservice{ @transactional(readonly = true) @override public page<persondto> search(final personcriteria criteria, final int pageindex) {     logger.debug("searching person set of criterias");      return new personpage(this.mapper.map(lists.newarraylist(this.personrepository.findall(personlitstquery(criteria))),             persondto.class), constructpagespecification(pageindex), count(criteria)); } 

the mapper use extending bit dozermapper:

public class dozermapper{ private final org.dozer.mapper mapper;  public dozermapper(final org.dozer.mapper mapper) {     this.mapper = mapper; }  @override public <t> t map(final object source, final class<t> destinationclass) {     return this.mapper.map(source, destinationclass); }  @override public <t> list<t> map(final list<?> sources, final class<t> destinationclass) {     final list<t> result = lists.newarraylist();     (final object source : sources) {         result.add(map(source, destinationclass));     }     return result; } 

now, of above works, fine unit tested , returns results want. problem controller , views....

i have read oliver's answer question: spring mvc 3: return spring-data page json

though reason cannot make work. i've added following dependencies project use hateoas , spring-data-commons:

<dependency>     <groupid>org.springframework.hateoas</groupid>     <artifactid>spring-hateoas</artifactid>     <version>0.7.0.release</version> </dependency> <dependency>     <groupid>org.springframework.data</groupid> <artifactid>spring-data-commons</artifactid> <version>1.6.0.release</version> </dependency> 

and controller looks this:

@controller @sessionattributes("person") public class personcontroller  @requestmapping(value = request_mapping_list, method = requestmethod.get) public httpentity<pagedresources> persons(final model model, @modelattribute final personcriteria searchcriteria,         final pageable pageable, final pagedresourcesassembler assembler) {     model.addattribute(model_attribute_searchcriteria, searchcriteria);     final page<persondto> persons = this.personservice.search(searchcriteria, searchcriteria.getpageindex());     return new responseentity<>(assembler.toresource(persons), httpstatus.ok); } 

and jsp:

<html> <head>     <title>testing</title>     <script src="jslinks jqgrid , jquery" type="text/javascript"></script> </head> <body> <form:form action="person" commandname="searchcriteria" method="post">     <div>         <form:label path="code">code: </form:label>         <form:input path="code" type="text"/>         <form:label path="surname">surname: </form:label>         <form:input path="surname" type="text"/>         <form:label path="firstname">firstname: </form:label>         <form:input path="firstname" type="text"/>         <form:label path="creationdatefrom">creation date from: </form:label>         <smj:datepicker id="creationdatefrom" name="creationdatefrom" />         <form:label path="creationdateto">creation date to: </form:label>         <smj:datepicker id="creationdateto" name="creationdateto" />     </div>     <div>         <input type="submit" value="search"/>     </div> </form:form>      <smjg:grid          gridmodel="gridmodel"          id="persons"          datatype="\"json\""         url="\'person\'"         jsonreader="{root:\"content\", repeatitems: false, records: \"numberofelements\", total: \"totalpages\"}">         <smjg:gridcolumn name="code" />         <smjg:gridcolumn name="surname" align="left"/>         <smjg:gridcolumn name="firstname" align="left"/>     </smjg:grid> </body> </html> 

explanation: smj , smjg tags taglibs i'm working on linking jquery spring mvc. ex: smjg:grid create tag , javascript call jqgrid function.

the first difference olivier's answer post spring mvc 3: return spring-data page json if infer persondto within httpentity following compilation error:

type mismatch: cannot convert responseentity<pagedresources> httpentity<pagedresources<persondto>> 

the second difference seems should infer persondto pagedresourcesassembler, correct?

the outcome when call url directly localhost:8081/app/person http 500 error:

org.springframework.http.converter.httpmessagenotwritableexception: not marshal [pagedresource { content: [resource { content: com.app.admin.service.persondto@60a349d0[id=2050,code=test2,firstname=chadsdatest,surname=francois,creationdate=<null>], links: [] }, resource { content: com.app.admin.service.persondto@48462da5[id=5050,code=testnew,firstname=francois,surname=asdasdx,creationdate=<null>], links: [] }, resource { content: com.app.admin.crediadmin.service.persondto@5458c9fc[id=51,code=test,firstname=francois,surname=asdawdsx,creationdate=<null>], links: [] }, resource { content: com.app.admin.service.persondto@de47c70[id=2051,code=test3,firstname=chaqweqasdamsh,surname=frasda,creationdate=<null>], links: [] }, resource { content: com.app.admin.service.persondto@7bd2085d[id=3053,code=test7,firstname=francois,surname=cadsdsx,creationdate=<null>], links: [] }, resource { content: com.app.admin.service.persondto@14676697[id=3050,code=tester,firstname=francois,surname=casdadsixchaix,creationdate=<null>], links: [] }, resource { content: com.app.admin.service.persondto@109de504[id=3051,code=tester3,firstname=francoisf,surname=chtest,creationdate=<null>], links: [] }], metadata: metadata { number: 0, total pages: 2, total elements: 7, size: 5 }, links: [<http://localhost:8081/app/person?page=1&size=5&sort=surname,asc>;rel="next"] }]: null; nested exception javax.xml.bind.marshalexception - linked exception: [com.sun.istack.saxexception2: unable marshal type  "org.springframework.hateoas.resource" element because not known context.] org.springframework.http.converter.xml.jaxb2rootelementhttpmessageconverter.writetoresult(jaxb2rootelementhttpmessageconverter.java:99) org.springframework.http.converter.xml.abstractxmlhttpmessageconverter.writeinternal(abstractxmlhttpmessageconverter.java:66) org.springframework.http.converter.abstracthttpmessageconverter.write(abstracthttpmessageconverter.java:179) org.springframework.web.servlet.mvc.method.annotation.abstractmessageconvertermethodprocessor.writewithmessageconverters(abstractmessageconvertermethodprocessor.java:148) org.springframework.web.servlet.mvc.method.annotation.httpentitymethodprocessor.handlereturnvalue(httpentitymethodprocessor.java:124) org.springframework.web.method.support.handlermethodreturnvaluehandlercomposite.handlereturnvalue(handlermethodreturnvaluehandlercomposite.java:69) org.springframework.web.servlet.mvc.method.annotation.servletinvocablehandlermethod.invokeandhandle(servletinvocablehandlermethod.java:122) 

and root cause:

javax.xml.bind.marshalexception - linked exception: [com.sun.istack.saxexception2: unable marshal type "org.springframework.hateoas.resource" element because not known context.] com.sun.xml.bind.v2.runtime.marshallerimpl.write(marshallerimpl.java:318) com.sun.xml.bind.v2.runtime.marshallerimpl.marshal(marshallerimpl.java:244) 

i'm not sure of wrong here.

althoug if call same url .json json output seems weird don't produce json still.

you've solved now, since have working thought i'd add solution @ least 1 of problems else in similar boat.

type mismatch: cannot convert responseentity<pagedresources> httpentity<pagedresources<persondto>>:

to solve this, add additional type parameter return type:

@requestmapping(value = request_mapping_list, method = requestmethod.get) public httpentity<pagedresources<persondto>> persons(final model model, @modelattribute final personcriteria searchcriteria,         final pageable pageable, final pagedresourcesassembler assembler) {     ... } 

com.sun.istack.saxexception2: unable marshal type "org.springframework.hateoas.resource" element because not known context.]

it looks spring trying produce xml, think default if finds jaxb implementation on classpath. if don't need produce xml method, add produces = {mediatype.application_json_value} @requestmapping.


Comments

Popular posts from this blog

image - ClassNotFoundException when add a prebuilt apk into system.img in android -

I need to import mysql 5.1 to 5.5? -

Java, Hibernate, MySQL - store UTC date-time -