I've been building a portion of an application to persist a user's dashboard objects and the JPA has been messing me up for ages.
I've got an abstract Widget class that all of the dashboard objects will be extending as more are developed. They are contained in a WidgetList class which is persisted through JPA. To me, the code looks good, but I'm still a novice with Java EE 6 and JPA. When I try to deploy, I get the following error:
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.开发者_JS百科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)
My WidgetList code is here:
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;
}
And, for the sake of completeness, the abstract Widget class that WidgetList is storing:
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;
}
}
This was written in Java EE 6, using JPA, deploying to a Glassfish 3.0.1 server using a MySQL database. I use NetBeans 6.9.1 as my development environment, with jdk 1.6.0_20 installed on my machine. We use this version due to dependencies we have with older software that we are still maintaining.
My understanding of the issue is that the @Id annotated field "id" on the WidgetList class is being identified as read-only. I have attempted to manually force it to recognize it as a non-read-only field via my use of the @Column annotation, but to no avail.
I've been hunting through the oracle forums, here at stackoverflow and anywhere google can take me, but I have had absolutely no luck in finding a solution. I had high hopes for the EclipseLink wiki page, but it has proved to be a bust as well. The actual error description tells me nothing.
If anyone has any ideas at all, they would be greatly appreciated.
Thanks, Matt Tatham
I don't fully understand why this particular error occured, but it seems that I was using the @MapsId annotation incorrectly. From the documentation I've been able to find, the annotation is supposed to be used to link to an @EmbeddedId primary key in another class. I was using it to map to the id that was part of my class, which JPA will do implicitly without having to be told.
Removing the @MapsId tag resolved the issue and allowed JPA to create my database tables without issue.
Ancient question, I know, but, briefly: this inscrutable message indicates only that you have an abstract entity with no concrete descendant entities defined or discoverable anywhere. That's it. It has nothing to do with sequences, or read-only mappings, or anything like that. Add a dummy concrete entity that extends from Widget
and you will be fine.
I faced the same problem.
EclipseLink simply doesn't like updatable = true
in @Column
when it comes to @Id
.
I haven 't used EclipseLink myself, but perhaps you have to define the Sequence to use? Take a look @ Specifying a Sequence. Not sure, the error message does not really make sense.
I had the same error lately. It appears to me it might caused by using InheritanceType.JOINED
strategy for the base abstract entity.
Using SINGLE_TABLE
(default) on the abstract superclass and JOINED
on subclasses works for me.
精彩评论