我正在尝试使用JAX-RS构建一个REST端点,以JSON格式返回JPA实体。 我找到了类似的question 但即使在我的情况下应用所有类似的更改后,我仍然会收到HTTP 500内部错误代码,而Glassfish不会生成任何日志或显示与此请求相关的错误消息。
以下是代码:
实体类:
@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配置:
@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
时我得到一个HTTP 500内部错误代码页,Glassfish返回一个空HTML 用: “服务器遇到内部错误,导致无法完成此请求。”
当我尝试搜索日志文件时,我看到没有错误,并且正在通过服务层进行调用并返回:
[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]]
即使日志显示没有错误和正在进行的调用,我也无法真正看到错误源是什么,只能看到默认的HTTP 500内部错误页面。
在注释掉FileReference类的@ManyToOne JPA实体关系后,我可以获得HTTP 200和JSON输出,如:
[
{
"@type":"bannerImage",
"id":1,
"type":"main"
},
{
"@type":"bannerImage",
"id":2,
"type":"main"
},
...
实体关系中的 @ManyToOne(fetch=FetchType.LAZY)
如果我切换到@ManyToOne(fetch=FetchType.EAGER)
然后我得到一个JSON响应,所以我猜这个问题与原始请求期间FileReference实例为空有关。
[
{
"@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属性不在我的模型上,并且与我无法准确确定它来自何处,也许是因为“查询”方法的响应类型是泛型类型List<T>
答案 0 :(得分:1)
问题恰好与EntityMapping FetchType.LAZY有关 在重构之后,我可以在包括:
之后获得正确的JSON响应在BannerImageService.java上:
@Override
protected String getDefaultQuery() {
return BannerImageDAO.GET_ALL_FETCH_FILE_REF;
}
并在BannerImageDAO中:
public static final String GET_ALL_FETCH_FILE_REF = "SELECT a FROM BannerImage a join fetch a.fileReference";
手动获取关系后,JSON响应是正确的。唯一奇怪的一点是,Glassfish没有记录任何与HTTP 500内部错误相关的异常或任何相关信息,但我想这是另一个话题。
答案 1 :(得分:1)
启用异常跟踪记录 - &gt;你应该实现一个ExceptionMapper
@Provider
public class ExceptionMapper implements javax.ws.rs.ext.ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
exception.printStackTrace();
return Response.status(500).build();
}
}
答案 2 :(得分:0)
7 年后,在几乎没有信息的情况下遇到了同样的 500。
Weblogic 12.2.1.3,EclipseLink 2.6.5。
指定 int rem = m - maxlength;
System.out.println(message.substring(0, message.length() - rem));
System.out.println(message.substring(message.length() - rem));
。
已申请 FetchType.LAZY on @OneToMany
。
没有在任何实体上应用@XmlRootElement。
这将返回 JPA 对象图的完整 JSON 表示。
[Oracle 参考][1]
[1]:http://wiki.eclipse.org/EclipseLink/Examples/REST/GettingStarted/XmlBinding