我一直在构建一个应用程序的一部分来持久保存用户的仪表板对象,并且JPA一直困扰着我。
我有一个抽象的Widget类,所有的仪表板对象都会随着更多的开发而扩展。它们包含在WidgetList类中,该类通过JPA持久化。对我来说,代码看起来不错,但我仍然是Java EE 6和JPA的新手。当我尝试部署时,出现以下错误:
Exception [EclipseLink-41] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: A non-read-only mapping must be defined for the sequence number field.
Descriptor: RelationalDescriptor(ui.dashboard.widgetlist.WidgetList --> [DatabaseTable(WIDGETLIST)])
Runtime Exceptions:
---------------------------------------------------------
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:478)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:406)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:671)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:620)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:228)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:369)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:151)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:207)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:202)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper._getDelegate(EntityManagerWrapper.java:197)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.createNamedQuery(EntityManagerWrapper.java:554)
at ca.comdev.cdip.mis.enterpriseportal.workflow.task.reminder.ReminderJpaDao.readAll(ReminderJpaDao.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1056)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1128)
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5292)
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:615)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:797)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:567)
at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:858)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:797)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:567)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:157)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:139)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:858)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:797)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:367)
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5264)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5252)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:190)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:84)
at $Proxy188.readAll(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:127)
at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43)
at workflow.task.reminder.ReminderDao_$$_javassist_79.readAll(ReminderDao_$$_javassist_79.java)
at workflow.task.reminder.ReminderSchedulerImpl.retrieveAllReminders(ReminderSchedulerImpl.java:117)
at workflow.task.reminder.ReminderSchedulerImpl.initialize(ReminderSchedulerImpl.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept(InterceptorManager.java:1006)
at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:61)
at com.sun.ejb.containers.interceptors.CallbackInvocationContext.proceed(CallbackInvocationContext.java:109)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCallback(SystemInterceptorProxy.java:133)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.init(SystemInterceptorProxy.java:115)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.ejb.containers.interceptors.CallbackInterceptor.intercept(InterceptorManager.java:961)
at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:61)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:390)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:373)
at com.sun.ejb.containers.AbstractSingletonContainer.createSingletonEJB(AbstractSingletonContainer.java:521)
at com.sun.ejb.containers.AbstractSingletonContainer.access$100(AbstractSingletonContainer.java:74)
at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.create(AbstractSingletonContainer.java:696)
at com.sun.ejb.containers.AbstractSingletonContainer.instantiateSingletonInstance(AbstractSingletonContainer.java:444)
at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:213)
at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:174)
at org.glassfish.ejb.startup.SingletonLifeCycleManager.doStartup(SingletonLifeCycleManager.java:152)
at org.glassfish.ejb.startup.EjbApplication.start(EjbApplication.java:150)
at org.glassfish.internal.data.EngineRef.start(EngineRef.java:126)
at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:241)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:236)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:339)
at com.sun.enterprise.v3.server.ApplicationLoaderService.processApplication(ApplicationLoaderService.java:362)
at com.sun.enterprise.v3.server.ApplicationLoaderService.postConstruct(ApplicationLoaderService.java:185)
at com.sun.hk2.component.AbstractWombImpl.inject(AbstractWombImpl.java:174)
at com.sun.hk2.component.ConstructorWomb$1.run(ConstructorWomb.java:87)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.hk2.component.ConstructorWomb.initialize(ConstructorWomb.java:84)
at com.sun.hk2.component.AbstractWombImpl.get(AbstractWombImpl.java:77)
at com.sun.hk2.component.SingletonInhabitant.get(SingletonInhabitant.java:58)
at com.sun.hk2.component.LazyInhabitant.get(LazyInhabitant.java:107)
at com.sun.hk2.component.AbstractInhabitantImpl.get(AbstractInhabitantImpl.java:60)
at com.sun.enterprise.v3.server.AppServerStartup.run(AppServerStartup.java:236)
at com.sun.enterprise.v3.server.AppServerStartup.start(AppServerStartup.java:128)
at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:457)
at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:401)
at org.jvnet.hk2.osgiadapter.HK2Main.start(HK2Main.java:125)
at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:640)
at org.apache.felix.framework.Felix.activateBundle(Felix.java:1700)
at org.apache.felix.framework.Felix.startBundle(Felix.java:1622)
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:915)
at org.jvnet.hk2.osgimain.Main.start(Main.java:140)
at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:640)
at org.apache.felix.framework.Felix.activateBundle(Felix.java:1700)
at org.apache.felix.framework.Felix.startBundle(Felix.java:1622)
at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1077)
at org.apache.felix.framework.StartLevelImpl.run(StartLevelImpl.java:264)
at java.lang.Thread.run(Thread.java:619)
我的WidgetList代码在这里:
package ui.dashboard.widgetlist;
import principals.Principal;
import ui.dashboard.widgets.Widget;
import java.io.Serializable;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MapsId;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
/**
* The storage class for the Widgets that a user has saved to their
* profile.
* @author mtatham
*/
@Entity
@Table(name="WIDGETLIST")
@NamedQueries({
@NamedQuery(name="widgetlist.byOwner",query="select w from WidgetList w where w.owner = :owner")
})
public class WidgetList implements Serializable {
/**
* The system generated ID
*/
@Id
@GeneratedValue
@Column(name="WIDGETLIST_ID", nullable = false, insertable=true,updatable=true )
private Integer id;
/**
* The user principal used for the lookup on the database
*/
@OneToOne @MapsId
private Principal owner;
/**
* The Set of Widgets associated with the owner.
*/
@OneToMany(mappedBy="currentWidgetList", cascade=CascadeType.ALL, orphanRemoval=true,fetch=FetchType.LAZY)
private Set<Widget> widgetList = new LinkedHashSet<Widget>();
public Integer getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Principal getOwner() {
return owner;
}
public void setOwner(Principal owner) {
this.owner = owner;
}
public Set<Widget> getWidgetList() {
return this.widgetList;
}
public void setWidgetList(Set<Widget> widgetList) {
this.widgetList = widgetList;
}
/**
* Adds a new Widget to the Set. If the set already contains the
* unique Widget being added, the method will end gracefully.
* @param widget
*/
public void addWidget(Widget widget) {
if(this.widgetList.contains(widget)){
return;
}else {
widget.setCurrentWidgetList(this);
this.widgetList.add(widget);
}
}
@Override
public String toString() {
if(getOwner()!=null){
return getId() + " - " + getOwner().getName();
} else{
return getId().toString();
}
}
public boolean equals(WidgetList wl) {
return true;
}
并且,为了完整起见,WidgetList正在存储的抽象Widget类:
import ui.dashboard.widgetlist.WidgetList;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* This is the class used as the template for all of the customized widgets
* that will be included on the Enterprise Portal dashboard. This abstract
* class will contain the generic information required for the user's
* customized dashboard.
*
* Any new widgets for the dashboard must extend this class and add their
* custom data elements.
* @author mtatham
*/
@Entity
@Table(name = "WIDGETS")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE")
public abstract class Widget implements Serializable{
/**
* The ID of the Widget. Generated programmatically.
*/
@Id
@GeneratedValue
@Column(name="WIDGET_ID")
private int id;
/**
* The id name used on the JSF page to identify the object
*/
@Column(name = "IDNAME")
private String idName;
/**
* The WidgetList this Widget is currently assigned to.
*/
@ManyToOne(optional=false)
@JoinColumn(name = "CURRENT_WIDGETLIST_ID", nullable=false)
private WidgetList currentWidgetList;
/**
* Header name that is visible on the widget menu
*/
@Column(name = "HEADER")
private String headerName;
/**
* JSF property that determines if a user can hide the widget. This will
* be defaulted to 'true'. The only other value acceptable is 'false'.
*
* This is a String element even though there are only boolean values
* due to the data being used in the xhtml pages.
*/
@Column(name = "TOGGLEABLE")
private String toggleable = "true";
/**
* JSF property that determines if a user can close a widget to remove it
* from the dashboard. This will be defaulted to 'true'. The only other
* value acceptable is 'false'.
*
* This is a String element even though there are only boolean values
* due to the data being used in the xhtml pages.
*/
@Column(name = "CLOSABLE")
private String closable = "true";
/**
* This is an override to change the CSS style on the widget.
*/
@Column(name = "STYLE")
private String style;
/**
* Determines what part of the widget can be grabbed with the cursor to
* move it around. The default will be the header of the widget.
*/
@Column(name = "HANDLE")
private String handle = ".ui-panel-titlebar";
/**
* Determines the transparency of the widget while it is being dragged.
* This is a decimal number between 0 and 1. The default will be 1.
*/
@Column(name = "OPACITY")
private String opacity = "1";
/**
* This is the form object that the widget will be loaded into. This will
* be defaulted to widgetTemplate.xhtml. It can be overwritten in the
* extended classes.
*/
@Column(name="FORM")
private String xhtmlForm = "";
public WidgetList getCurrentWidgetList() {
return currentWidgetList;
}
public void setCurrentWidgetList(WidgetList widgetList) {
this.currentWidgetList = widgetList;
}
public String getClosable() {
return closable;
}
public String getHandle() {
return handle;
}
public String getHeaderName() {
return headerName;
}
public int getId() {
return id;
}
public String getIdName() {
return idName;
}
public String getOpacity() {
return opacity;
}
public String getStyle() {
return style;
}
public String getToggleable() {
return toggleable;
}
public String getXhtmlForm() {
return xhtmlForm;
}
public void setClosable(String closable) {
this.closable = closable;
}
public void setHandle(String handle) {
this.handle = handle;
}
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
public void setId(int id) {
this.id = id;
}
public void setIdName(String idName) {
this.idName = idName;
}
public void setOpacity(String opacity) {
this.opacity = opacity;
}
public void setStyle(String style) {
this.style = style;
}
public void setToggleable(String toggleable) {
this.toggleable = toggleable;
}
public void setXhtmlForm(String xhtmlForm) {
this.xhtmlForm = xhtmlForm;
}
}
这是用Java EE 6编写的,使用JPA,使用MySQL数据库部署到Glassfish 3.0.1服务器。我使用NetBeans 6.9.1作为我的开发环境,在我的机器上安装了jdk 1.6.0_20。我们使用此版本是因为我们对旧软件的依赖性仍然存在。
我对该问题的理解是WidgetList类上的@Id带注释字段“id”被标识为只读。我试图通过使用@Column注释手动强制它将其识别为非只读字段,但无济于事。
我一直在寻找oracle论坛,在stackoverflow和谷歌可以带我的任何地方,但我找到一个解决方案绝对没有运气。我对EclipseLink wiki page寄予厚望,但事实证明它也是一个半身像。实际的错误描述什么也没告诉我。
如果有人有任何想法,他们将不胜感激。
谢谢, 马特塔特姆
答案 0 :(得分:2)
我不完全理解为什么会发生这种特殊错误,但似乎我错误地使用了@MapsId注释。从我能够找到的文档中,注释应该用于链接到另一个类中的@EmbeddedId主键。我正在使用它来映射到我班级的id,JPA将隐式执行而不必被告知。
删除@MapsId标记解决了该问题,并允许JPA无问题地创建我的数据库表。
答案 1 :(得分:1)
古老的问题,我知道,但是,简单地说:这个不可思议的消息只表明你有一个抽象的实体,没有任何具体的后代实体定义或可在任何地方发现。而已。它与序列,只读映射或类似的东西无关。添加一个从Widget
延伸的虚拟混凝土实体,你会没事的。
答案 2 :(得分:0)
我自己没有使用过EclipseLink,但也许您必须定义要使用的Sequence?看看@ Specifying a Sequence。不确定,错误信息确实没有意义。
答案 3 :(得分:0)
我最近有同样的错误。在我看来,它可能是由基础抽象实体使用InheritanceType.JOINED
策略引起的。
在抽象超类上使用SINGLE_TABLE
(默认值),在子类上使用JOINED
对我有用。
答案 4 :(得分:0)
我遇到了同样的问题。
对于updatable = true
,EclipseLink根本不喜欢@Column
中的@Id
。