JAXB on JAX-RS - JPA Entity with relations returns no JSON HTTP 500 no error on logs (Glassfish) -
i trying build rest endpoint using jax-rs return jpa entities in json format. found similar question though after applying similar changes in case still http 500 internal error code , glassfish produces no log or shows no error messages related request.
here code:
entity class:
@xmlrootelement @entity @table(name = "tb_banner_image") public class bannerimage extends baseentity<integer> { private filereference filereference; private string type; private string labeltitle; private string labeltext; public bannerimage() {} @id @tablegenerator(name="genbannerimage", table="tb_id_generator", pkcolumnname="id_name", valuecolumnname="id_val", pkcolumnvalue="tb_banner_image", allocationsize=1) @generatedvalue(strategy=generationtype.table, generator="genbannerimage") @column(name = "id_banner_image", unique = true, nullable = false) public integer getid() { return super.getid(); } @override public void setid(integer id) { super.setid(id); } @column(name="type") public string gettype() { return type; } public void settype(string type) { this.type = type; } @manytoone(fetch=fetchtype.lazy) @joincolumn(name="id_file_reference", nullable=false) public filereference getfilereference() { return filereference; } public void setfilereference(filereference filereference) { this.filereference = filereference; } @column(name="label_title") public string getlabeltitle() { return labeltitle; } public void setlabeltitle(string labeltitle) { this.labeltitle = labeltitle; } @column(name="label_text") public string getlabeltext() { return labeltext; } public void setlabeltext(string labeltext) { this.labeltext = labeltext; } }
and
@xmlrootelement @entity @table(name = "tb_file_reference") public class filereference extends basenamedentity<string> { private string type; public filereference() {} @id @tablegenerator(name="genfilereference", table="tb_id_generator", pkcolumnname="id_name", valuecolumnname="id_val", pkcolumnvalue="tb_file_reference", allocationsize=1) @generatedvalue(strategy=generationtype.table, generator="genfilereference") @column(name = "id_file_reference", unique = true, nullable = false) public string getid() { return super.getid(); } @override public void setid(string id) { super.setid(id); } @column(name = "type") public string gettype() { return type; } public void settype(string type) { this.type = type; } }
base generic superclass:
@mappedsuperclass public abstract class basenamedentity<id extends serializable> implements inamedentity<id>, comparable, serializable { private id id; private string name; protected basenamedentity() {} public string getname() { return name; } public void setname(string name) { this.name = name; } @transient public id getid() { return id; } public void setid(id id) { this.id = id; } @override public boolean equals(object obj) { if (obj != null && obj instanceof basenamedentity) { basenamedentity base2 = (basenamedentity) obj; if (this.getid() != null && base2.getid() != null) { return this.getid().equals(base2.getid()); } } return false; } @override public int hashcode() { return super.hashcode(); } @override public string tostring() { return name; } @override public int compareto(object arg0) { if (this == arg0) { return 0; } basenamedentity<id> other = (basenamedentity<id>) arg0; return getname().compareto(other.getname()); } }
application jax-rs configuration:
@applicationpath("/rest") public class portalapplication extends application { @override public set<class<?>> getclasses() { final set<class<?>> classes = new hashset<class<?>>(); // register root resource classes.add(bannerimageservice.class); return classes; } }
service class:
@path("/banner") public class bannerimageservice extends baseservicefacade<bannerimage, integer> { public bannerimageservice() { super(bannerimage.class); } @override protected boolean validateentity(bannerimage entity) { if (entity != null && entity.getid() != null && entity.getfilereference() != null && entity.getfilereference().getname() != null && regexutil.getinstance().validatefilename( entity.getfilereference().getname())) { return true; } return false; } @override protected string getdefaultquery() { return null; } @override protected boolean validateid(integer id) { return regexutil.getinstance().validateintegerid(id); } @override public crud<bannerimage, integer> lookupservice() throws servicelocatorexception { return servicelocator.getinstance() .getlocalhome(servicesconstants.banner_image_service); } }
and
public abstract class baseservicefacade<t extends ientity<id>, id extends serializable> implements servicefacaderest<t, id> { protected static final logger log = logger.getlogger("baseservicefacade"); protected crud<t, id> service; protected class<t> clazz; public baseservicefacade(class<t> classe) { clazz = classe; } protected abstract boolean validateentity(t entity); protected abstract boolean validateid(id id); protected abstract string getdefaultquery(); protected abstract crud<t, id> lookupservice() throws servicelocatorexception; public crud<t,id> getservice() { try { if (service == null) { service = lookupservice(); } }catch (exception ex) { logexception(ex); } return service; } public void setservice(crud<t,id> service) { this.service = service; } public class<t> getclazz() { return clazz; } public void serviceexception(serviceexception ex) { log.log(level.info, ex.getmessage()); } public void logexception(exception ex) { log.log(level.info, ex.getmessage()); ex.printstacktrace(); } @override @get @produces({mediatype.application_xml, mediatype.application_json}) @path("/query") public list<t> query() { try { string defaultquery = getdefaultquery(); if (defaultquery != null) { return getservice().search(defaultquery); } else { return getservice().findall(clazz); } } catch (serviceexception e) { serviceexception(e); } catch (exception ex) { logexception(ex); } return null; } @override @get @consumes(mediatype.application_json) @produces({mediatype.application_xml, mediatype.application_json}) @path("/get/{id}") public t get(@pathparam("id") id id) { try { if (validateid(id)) { return getservice().findbyid(clazz, id); } } catch (serviceexception e) { serviceexception(e); } catch (exception ex) { logexception(ex); } return null; } @override @post @consumes(mediatype.application_json) @produces({mediatype.application_xml, mediatype.application_json}) @path("/create") public t create(t entity) { try { if (validateentity(entity)) { getservice().insert(entity); return entity; } } catch (serviceexception e) { serviceexception(e); } catch (exception ex) { logexception(ex); } return null; } @override @put @produces({mediatype.application_xml, mediatype.application_json}) @path("/update/{id}") public t update(t entity) { try { if (validateentity(entity)) { return getservice().update(entity); } } catch (serviceexception e) { serviceexception(e); } catch (exception ex) { logexception(ex); } return null; } @override @delete @produces({mediatype.application_xml, mediatype.application_json}) @path("/delete/{id}") public boolean delete(@pathparam("id") id id) { try { if (validateid(id)) { return getservice().delete(clazz, id); } } catch (serviceexception e) { serviceexception(e); } catch (exception ex) { logexception(ex); } return false; } }
when hit localhost/app/rest/banner/query
i http 500 internal error code page , glassfish returns empty html : "the server encountered internal error prevented fulfilling request."
when try search log files see no errors, , calls being made through service layers , back:
[2014-03-19t20:39:28.898-0300] [glassfish 4.0] [fine] [] [org.eclipse.persistence.session.file[tid: _threadid=20 _threadname=http-listener-1(1)] [timemillis: 1395272368898] [levelvalue: 500] [[ select id_banner_image, label_text, label_title, type, id_file_reference tb_banner_image]]
even though logs show no errors , calls being made, ui can't see what's error source, default http 500 internal error page.
after commenting out @manytoone jpa entity relation of filereference class http 200 , json output like:
[ { "@type":"bannerimage", "id":1, "type":"main" }, { "@type":"bannerimage", "id":2, "type":"main" }, ...
in entity relation @manytoone(fetch=fetchtype.lazy)
if switch @manytoone(fetch=fetchtype.eager)
then json response guess issue related filereference instance being null during original request.
[ { "@type":"bannerimage", "id":1, "filereference":{ "id":"2bdbb063d0d0ee2939c89763945d9d9e", "name":"banner1.png", "type":"image/png" }, "type":"main" }, { "@type":"bannerimage", "id":2, "filereference":{ "id":"b33fa2041f2989f58a25dca2a6a35025", "name":"banner2.png", "type":"image/png" }, "type":"main" },
but there @type attribute not on model , created alongside can't determine precisely it's coming from, perhaps it's due response type of "query" method being generic type list<t>
the issue happened related entitymapping fetchtype.lazy after refactoring correct json response after including:
on bannerimageservice.java:
@override protected string getdefaultquery() { return bannerimagedao.get_all_fetch_file_ref; }
and in bannerimagedao:
public static final string get_all_fetch_file_ref = "select bannerimage join fetch a.filereference";
after manually fetching relation json response correct. strange point glassfish didn't log exceptions or related info related http 500 internal error, guess topic.
Comments
Post a Comment