JAX-RS上的JAXB - JPA实体与关系返回没有JSON HTTP 500没有日志错误(Glassfish) [英] JAXB on JAX-RS - JPA Entity with relations returns no JSON HTTP 500 no error on logs (Glassfish)

查看:99
本文介绍了JAX-RS上的JAXB - JPA实体与关系返回没有JSON HTTP 500没有日志错误(Glassfish)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用JAX-RS构建一个REST端点,以JSON格式返回JPA实体。
我发现了一个类似的问题
但是即使在我的情况下应用所有类似的更改之后我仍然得到HTTP 500内部错误代码而Glassfish没有生成日志或显示没有与此请求相关的错误消息。

I am trying to build a REST endpoint using JAX-RS to return JPA entities in JSON format. I found a similar question but even though after applying all similar changes in my case I still get HTTP 500 Internal Error code and Glassfish produces no log or shows no error messages related with this request.

以下是代码:

实体类:

@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;
    }

}

@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;
    }

}

基础通用超类:

@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());
    }
}

应用程序JAX-RS配置:

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;
    }
}

服务等级:

@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);      
    }   
}

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;
    }

}

当我点击localhost / app / rest / banner / query

When I hit localhost/app/rest/banner/query

我得到一个HTTP 500内部错误代码页,Glassfish返回一个空的HTML

服务器遇到了阻止它完成此请求的内部错误。

I get a HTTP 500 internal Error code page and Glassfish returns an empty HTML with : "The server encountered an internal error that prevented it from fulfilling this request."

当我尝试搜索日志文件时,我看到没有错误,并且正在通过服务层和返回:

When I try to search the log files I see no errors, and the calls are being made through the service layers and 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 FROM TB_BANNER_IMAGE]]

即使日志显示没有错误和正在进行的调用,也来自UI我实际上无法看到错误源是什么,只有默认的HTTP 500内部错误页面。

even though the logs show no errors and the calls being made, from the UI I can't actually see what's the error source, only a default HTTP 500 Internal Error page.

在FileReference类的@ManyToOne JPA实体关系中,我可以获得HTTP 200和JSON输出,如:

After commenting out the @ManyToOne JPA Entity Relation of FileReference class I could get a HTTP 200 and JSON output like:

[
{
"@type":"bannerImage",
"id":1,
"type":"main"
},
{
"@type":"bannerImage",
"id":2,
"type":"main"
},
...

@ManyToOne(fetch = FetchType.LAZY)
如果我切换到 @ManyToOne(fetch = FetchType.EAGER)

然后我得到一个JSON响应所以我猜这个问题与原始请求期间FileReference实例为空有关。

then I get a JSON response so I guess the issue is related to the FileReference instance being null during the 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"
},

但是有一个@type属性不在我的模型上,并且是我无法准确确定它来自哪里,也许是由于的响应类型查询方法是泛型类型列表< T>

but there is a @type attribute which is not on my model and is created alongside which I can't determine precisely from where it's coming from, perhaps it's due to the response type of the "query" method being a generic type List<T>

推荐答案

问题恰好与重构后的EntityMapping FetchType.LAZY
有关我在BanImageService.java上包含:

The issue happened to be related to the EntityMapping FetchType.LAZY after refactoring I could get a correct JSON response after including:

之后可以获得正确的JSON响应:

on BannerImageService.java:

@Override
protected String getDefaultQuery() {
    return BannerImageDAO.GET_ALL_FETCH_FILE_REF;
}

和BannerImageDAO:

and in BannerImageDAO:

public static final String GET_ALL_FETCH_FILE_REF = "SELECT a FROM BannerImage a join fetch a.fileReference";

手动获取JSON响应正确的关系后。唯一奇怪的一点是,Glassfish没有记录任何与HTTP 500内部错误相关的异常或任何相关信息,但我想这是另一个主题。

after manually fetching the relation the JSON response was correct. The only strange point is that Glassfish didn't log any exceptions or any related info related to the HTTP 500 Internal Error, but I guess this is another topic.

这篇关于JAX-RS上的JAXB - JPA实体与关系返回没有JSON HTTP 500没有日志错误(Glassfish)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆