I have the following problem with a method of JPA.
I can not delete an item from a collection.
Actually, the method only works if it is not the last element inserted.
Where I'm wrong?
This is the class of my model:
#Entity
public class JobOffer {
#SequenceGenerator(name="JobOffer_Gen", sequenceName="JobOffer_Seq", initialValue=1, allocationSize=1)
#Id #GeneratedValue(generator="JobOffer_Gen") #Column(name="ID_JOBOFFER")
private Long id;
#Column
private String title;
...
#OneToMany
#JoinTable(joinColumns = #JoinColumn(name = "JOBOFFER_IDFK"), inverseJoinColumns = #JoinColumn(name = "LANGUAGE_IDFK"))
private Collection<Language> languages = new HashSet<Language>();
...
}
This is my method in JPA:
#Override
#Transactional
public void deleteLanguage(JobOffer joboffer, Long idLingua) throws BusinessException {
for(Language l : joboffer.getLanguages()){
if (l.getId() == idLingua){
joboffer.getLanguages().remove(l);
}
}
em.merge(joboffer);
}
What is the correct way to search for an item in a collection and delete in JPA?
This is the error that I get from the console:
21-ott-2013 18.22.27 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() for servlet [jobbook] in context with path [/jobbook] threw exception [Request processing failed; nested exception is java.util.ConcurrentModificationException] with root cause
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at org.eclipse.persistence.indirection.IndirectList$1.next(IndirectList.java:571)
at it.univaq.mwt.j2ee.jobbook.business.impl.JPAJobOfferService.deleteLanguage(JPAJobOfferService.java:95)
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)
and then continues
You may try something like this:
#Override
#Transactional
public void deleteLanguage(JobOffer joboffer, Long idLingua) throws BusinessException {
Language language = em.createQuery("SELECT lang from Language lang where lang.jobOffer.id = :job_id", Language.class).setParameter("job_id", joboffer.getId()).getSingleResult();
if(language != null){
joboffer.getLanguages().remove(language);
}
}
Please note:
this is not tested
I assumed that your "Language" Entity has a reference to your JobOffer Entity. Although I do not know your domain, this may indicate a bad design
If the parameter joboffer is in detached state, then you have to reattach it to the current session (using em.merge()).
Edit: Adapted Query in response to the comment of DataNucleus.
Related
I have the following repository:
public interface ICredCardRepository extends JpaRepository<CredCardEntity, Long> {
public List<CredCardEntity> findByUserId(Long userId);
}
The UserId attribute is declared like this in the CredCardEntity:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "UserId", nullable = false)
private UserEntity UserId;
I have the following exception:
Caused by: java.lang.RuntimeException:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'ICredCardRepository': Invocation of init
method failed; nested exception is java.lang.IllegalArgumentException:
Could not create query metamodel for method public abstract
java.util.List
org.wpattern.frameworks.jsf.primefaces.model.repositories.ICredCardRepository.findByUserId(java.lang.Long)!
at
io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:223)
at
org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:87)
at
org.wildfly.extension.undertow.deployment.UndertowDeploymentService.start(UndertowDeploymentService.java:72)
at
org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1948)
[jboss-msc-1.2.2.Final.jar:1.2.2.Final] at
org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1881)
[jboss-msc-1.2.2.Final.jar:1.2.2.Final]
Based on this exception I have changed the method findByUserId like that:
public List<CredCardEntity> findByUserId(UserEntity userId);
But it does not work. Could you help me out, please?
Simply change UserId property name to user. In this case 'UserId' in your method will be pointed to the id property of the User.
Also I think #JoinColumn is unnecessary here, you can remove it...
I have this entity
#Entity
public class ContactList extends Base {
private static final long serialVersionUID = BaseEntity.serialVersionUID;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Collection<User> contacts = new HashSet<User>();
public ContactList() {
}
public Collection<User> getContacts() {
return contacts;
}
public void setContacts(Collection<User> contacts) {
this.contacts = contacts;
}
}
and whatever method I call from the Spring Data repository, like findAll(), I get this error
java.lang.NullPointerException: null
at org.datanucleus.store.rdbms.RDBMSStoreManager.assertCompatibleFieldType(RDBMSStoreManager.java:1005) ~[datanucleus-rdbms-4.1.1.jar:na]
at org.datanucleus.store.rdbms.RDBMSStoreManager.getBackingStoreForField(RDBMSStoreManager.java:965) ~[datanucleus-rdbms-4.1.1.jar:na]
at org.datanucleus.store.rdbms.query.BulkFetchExistsHelper.getSQLStatementForContainerField(BulkFetchExistsHelper.java:93) ~[datanucleus-rdbms-4.1.1.jar:na]
at org.datanucleus.store.rdbms.query.JPQLQuery.compileQueryFull(JPQLQuery.java:894) ~[datanucleus-rdbms-4.1.1.jar:na]
at org.datanucleus.store.rdbms.query.JPQLQuery.compileInternal(JPQLQuery.java:296) ~[datanucleus-rdbms-4.1.1.jar:na]
at org.datanucleus.store.query.Query.executeQuery(Query.java:1801) ~[datanucleus-core-4.1.1.jar:na]
at org.datanucleus.store.query.Query.executeWithMap(Query.java:1747) ~[datanucleus-core-4.1.1.jar:na]
at org.datanucleus.api.jpa.JPAQuery.getResultList(JPAQuery.java:197) ~[datanucleus-api-jpa-4.1.1.jar:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:77) ~[spring-data-jpa-1.3.0.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:55) ~[spring-data-jpa-1.3.0.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:95) ~[spring-data-jpa-1.3.0.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:85) ~[spring-data-jpa-1.3.0.RELEASE.jar:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:312) ~[spring-data-commons-1.5.0.RELEASE.jar:na]
Any idea why?
I also tried adding targetEntity = User.class to #ManyToMany.
I'm using DataNucleus 1.4.1.
I found in the log the following lines that could be relevant:
DataNucleus.Datastore.Schema - DEBUG: Field [ContactList.contacts] -> Column(s) [contactlist.contacts] using mapping of type "org.datanucleus.store.rdbms.mapping.java.TypeConverterMapping" (org.datanucleus.store.rdbms.mapping.datastore.VarCharRDBMSMapping)
...
DataNucleus.Persistence - WARN : Member ContactList.contacts in table=contactlist has mapping=org.datanucleus.store.rdbms.mapping.java.TypeConverterMapping#6296ccf7 but expected mapping type=class org.datanucleus.store.rdbms.mapping.java.CollectionMapping
The problem was that a Converter was automatically applied. But I think this is an issue with DataNucleus, because that converter was declared something like this
public class ListOfMyEnumsToStringAttributeConverter
extends CollectionOfEnumsToStringAttributeConverter<MyEnum, List<MyEnum>>
implements AttributeConverter<List<MyEnum>, String>
Another issue with DataNucleus is that NPE is thrown even though a warning/error message should be logged.
And last, but not least, when a converter is automatically applied and this leads to an error, the converter class should be part of the log message.
I'm doing a POC on a Hibernate OGM implementation for Neo4j. In doing this, I've created the following objects:
#Entity
public class AutoDealership {
private String name;
public AutoDealership(String nam){
this.name = nam;
}
#Id
public String getName(){
return name;
}
private void setName(String n){
name = n;
}
private List<Vehicle> vehicle = new ArrayList<Vehicle>();
#OneToMany(mappedBy="autoDealership")
public List<Vehicle> getVehicle(){
return vehicle;
}
private void setVehicles(List<Vehicle> v){
this.vehicle = v;
}
}
And a Vehicle class:
public abstract class Vehicle {
protected AutoDealership autoDealership;
abstract int getValue();
#ManyToOne
public abstract AutoDealership getAutoDealership();
private void setValue(int v){
}
}
Which is extended into classes that have simple implementations. I run this code as follows:
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
OgmSession session =em.unwrap(OgmSession.class);
Camry camry1 = new Camry("Joe");
Camry camry2 = new Camry("Elvis");
Silverado s = new Silverado("TX");
Maserati mas = new Maserati();
mas.setStatus("Massive");
session.saveOrUpdate(camry1);
session.saveOrUpdate(camry2);
session.saveOrUpdate(s);
session.saveOrUpdate(mas);
AutoDealership a = new AutoDealership("Slick Willie's");
session.saveOrUpdate(a);
camry1.setAutoDealership(a);
camry2.setAutoDealership(a);
mas.setAutoDealership(a);
s.setAutoDealership(a);
tx.commit();
em.close();
emf.close();
When I run this, it fails with :
Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: ogm-neo4j] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1239)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:855)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:845)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:398)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:844)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:75)
at org.hibernate.ogm.jpa.HibernateOgmPersistence.createEntityManagerFactory(HibernateOgmPersistence.java:62)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
at dogs.TestClass.main(TestClass.java:22)
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: cars.AutoDealership.vehicle[cars.Vehicle]
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1134)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:793)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:728)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:70)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1697)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1426)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
If I comment out anything related to getting the vehicles from AutoDealership, the code compiles and works, and successfully inserts nodes into the database. I've tried to change the mappedBy target to no avail.
It turns out that the problem was that I had to declare Vehicle as an Entity.
I've got a problem with EJB/Glassfish. I'm working on a client-server application in which the client creates an entity object and must send it to the server application, which must persist the entity in its database. I've choose to use session beans to communicate with the server.
I've implemented some simple cases in which a method in the session bean takes as input a string or an int and it works fine. The problem arises when I try to give an entity object as input.
I report my entity class:
#Entity
public class Example implements Serializable {
private static final long serialVersionUID = 1L;
#Id
String nome;
public void setNome(String nome) {
this.nome = nome;
}
public String getNome() {
return nome;
}
Here my session bean:
#Stateless
public class GestoreLibreriaRemoto implements GestoreLibreriaRemotoRemote {
#Override
public String getProva(Example prova) {
return prova.getNome();
}
Here my client application:
public class GestoreLibreriaLocale {
public static void assegnaCategoriaACopia(CopiaUtente copia, Categoria categoria) throws
public void prova() {
GestoreLibreriaRemotoRemote gestore = lookupGestoreLibreriaRemotoRemote();
Example example = new Example();
prova.setNome("hodor");
System.out.println(gestore.getProva(example));
}
private GestoreLibreriaRemotoRemote lookupGestoreLibreriaRemotoRemote() {
try {
Context c = new InitialContext();
return (GestoreLibreriaRemotoRemote) c.lookup("java:global/ServerMDB/ServerMDB-ejb/GestoreLibreriaRemoto");
} catch (NamingException ne) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
throw new RuntimeException(ne);
}
}
In my main class I simply call GestoreLibreriaLocale.prova() and i get the following error:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.glassfish.appclient.client.acc.AppClientContainer.launch(AppClientContainer.java:446)
at org.glassfish.appclient.client.AppClientFacade.main(AppClientFacade.java:166)
Caused by: javax.ejb.EJBException: java.rmi.MarshalException: CORBA MARSHAL 1330446346 Maybe; nested exception is:
org.omg.CORBA.MARSHAL: ----------BEGIN server-side stack trace----------
org.omg.CORBA.MARSHAL: AVVERTENZA: 00810010: Error from readValue on ValueHandler in CDRInputStream vmcid: OMG minor code: 10 completed: Maybe
at com.sun.proxy.$Proxy139.valuehandlerReadError(Unknown Source)
at com.sun.corba.ee.impl.encoding.CDRInputStream_1_0.readRMIIIOPValueType(CDRInputStream_1_0.java:912)
at com.sun.corba.ee.impl.encoding.CDRInputStream_1_0.read_value(CDRInputStream_1_0.java:1005)
at com.sun.corba.ee.impl.encoding.CDRInputObject.read_value(CDRInputObject.java:518)
at com.sun.corba.ee.impl.presentation.rmi.DynamicMethodMarshallerImpl$14.read(DynamicMethodMarshallerImpl.java:383)
at com.sun.corba.ee.impl.presentation.rmi.DynamicMethodMarshallerImpl.readArguments(DynamicMethodMarshallerImpl.java:450)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:171)
at com.sun.corba.ee.impl.protocol.ServerRequestDispatcherImpl.dispatchToServant(ServerRequestDispatcherImpl.java:528)
at com.sun.corba.ee.impl.protocol.ServerRequestDispatcherImpl.dispatch(ServerRequestDispatcherImpl.java:199)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequestRequest(MessageMediatorImpl.java:1549)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequest(MessageMediatorImpl.java:1425)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleInput(MessageMediatorImpl.java:930)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:213)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequest(MessageMediatorImpl.java:694)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.dispatch(MessageMediatorImpl.java:496)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.doWork(MessageMediatorImpl.java:2222)
at com.sun.corba.ee.impl.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
at com.sun.corba.ee.impl.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class com.sun.corba.ee.impl.io.IIOPInputStream
at com.sun.corba.ee.impl.io.ValueHandlerImpl.createInputStream(ValueHandlerImpl.java:820)
at com.sun.corba.ee.impl.io.ValueHandlerImpl.readValue(ValueHandlerImpl.java:263)
at com.sun.corba.ee.impl.encoding.CDRInputStream_1_0.readRMIIIOPValueType(CDRInputStream_1_0.java:903)
... 16 more
The error log continues, I don't report the whole log but if you need it I can post it.
Please help me, I'm working on it from days without resolving it.
Thanks for the attention,
Francesco
This seems to be a bug in the current Java versions (e.g. 1.7.0_55 and 1.8.0_05), have a look at this issue: GLASSFISH-21047
To make it work, install either an older or a newer Java version (e.g. 1.7.0_051 or 1.8.0_020).
See also:
Exception inside CORBA when accessing a remote bean
I bow to the apt stackoverflow community and humbly seek guidance (I bow my head in subservience as I write this)
I have the following Entity class/bean which has a mixture of JPA/EclipseLink/JAXB/Moxy annotations: (btw EventBase is just a #MappedSuperclass that holds additional fields)
#Entity
#Table(name = "EVENTS")
#XmlRootElement
public class Event extends EventBase {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#XmlAttribute(name = "id")
private long eventCID;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "APPLICATIONCID")
private CustomerApplication customerApplication;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CUSTOMERCID")
private Customer customer;
....
}
Here's my code to marshal this entity (outer class excluded for brevity)
public static void main(String args[]) {
Event event = myInstance.populateEvent();
myInstance.buildXMLFromEvent(event);
}
public Event populateEvent() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory(this.persistenceUnit);
EntityManager em = null;
Event event = null;
try {
em = emf.createEntityManager();
event = (Event) em.createQuery("Select object(e) from Event e where e.eventCID = 55000").getSingleResult();
em.clear();
em.detach(event);
em.close();
em = null;
emf.close();
emf = null;
} catch (Exception e) { // just test code so catching general exception
log.error("Unexpected error: " + e);
} finally {
if (em != null) {
em.clear();
em.close();
}
}
return event;
}
private void buildXMLFromEvent(Event event) {
System.out.println("Marshalling now:");
JAXBContext jc;
try {
jc = JAXBContext.newInstance(Event.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.valueOf(true));
JAXBElement<Event> jaxbElement = new JAXBElement<Event>(new QName("event"), Event.class, event);
marshaller.marshal(jaxbElement, System.out);
} catch (JAXBException e) {
}
}
The generated xml actually goes and eagerly fetches all of the member objects of my Event entity bean! i.e) Customer, CustomerApplication and any other mappings which I've excluded for brevity. I'm using EclipseLink as my JPA provider and Moxy for JAXB. What am I doing wrong here? You can see that not only are the entityManager AND entityManagerFactory instances cleared, closed and set to null, but I've also gone ahead and detached the root Event entity. Moreover, the fetchtype has explicitly been set to LAZY!
How is it that JAXB can eagerly fetch when the Event object has been detached? I thought closing the entityManager in itself detaches all managed objects? Is there some cached session context that JAXB is hanging on to? If so, why is it not even honoring the explicitly defined fetch strategy?
Many thanks in advance!
Ustad
If eclipselink is in standalone mode, then only ManyToMany and OneToMany relations is actually uses lazy-loading, for others fetch attribute is ignored and equal to EAGER.
Here is documentation for that http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Basic_Mappings/Lazy_Basics
One-to-one: By default, EclipseLink JPA ignores the fetch attribute and
default javax.persistence.FetchType.EAGER applies.
Many-to-one: EclipseLink JPA performs lazy loading when the fetch
attribute is set to javax.persistence.FetchType.LAZY.
Basic: By default, EclipseLink JPA ignores the fetch attribute and
default javax.persistence.FetchType.EAGER applies.
That`s why your entities are loaded with relations.
Hope it helps.