Class instance in the heap - java

I try to create a simple JPA application based on spring framework and Eclipselink JPA.
First of all initialize an EntityManagerBean:
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws Exception {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setJpaDialect(new EclipseLinkJpaDialect());
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setShowSql(true);
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.PostgreSQLPlatform");
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan("org.egzi.diplom.model");
entityManagerFactoryBean.setLoadTimeWeaver(new SimpleLoadTimeWeaver());
//to update existing table (alter table)+
Properties additionalProperties = new Properties();
additionalProperties.setProperty("eclipselink.ddl-generation", "create-or-extend-tables");
additionalProperties.setProperty("eclipselink.ddl-generation.output-mode","database");
entityManagerFactoryBean.setJpaProperties(additionalProperties);
return entityManagerFactoryBean;
}
And in a DAO class a try to persist some entity:
#PersistenceContext
EntityManager entityManager;
#Transactional(propagation = Propagation.REQUIRED)
public void createTODO() {
Todo todo = new Todo();
todo.setSummary("a");
todo.setDescription("b");
entityManager.persist(todo);
}
And entity class:
#Entity
public class Todo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String summary;
private String description;
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return "Todo [summary=" + summary + ", description=" + description
+ "]";
}
}
but when i run such code i have an exception:
java.lang.IllegalArgumentException: Object: Todo [summary=a, description=b] is not a known entity type.
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4228)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:496)
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.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:262)
at com.sun.proxy.$Proxy22.persist(Unknown Source)
at org.egzi.diplom.spring.GeneratorImpl.createTODO(GeneratorImpl.java:59)
and when i look into a eclipselink sources i find HashMap with Class as a key:
org.eclipse.persistence.internal.sessions.AbstactSession.getDescriptor(Class):
descriptor = this.descriptors.get(theClass);
When i started to debug my code i find that descriptors map already have a key of Todo.class. And i find that identityHash of class in HashMap and Todo.class is a different. I start my code from Inteliji IDEA.
What's wrong in my example?
UPDATE:
find that classes in descriptors HashMap have a link on org.springframework.instrument.classloading.SimpleInstrumentableClassLoader#14bb2297
but my Todo object have another one:
sun.misc.Launcher$AppClassLoader#58644d46

Try to add getter and setter for field ID too!

Fix exception by setting another LoadTimeWeaver - InstrumentationLoadTimeWeaver and exception is gone

Related

Spring Boot findById not working for MongoDB

I'm trying to do a simple get query on springboot using mongodb as database engine
I have tried with several stuff(sending the data as ObjectId and even changing the repository)
public ResponseEntity<Track> get(String trackId) {
Track find = mongoTemplate.findById(new ObjectId(trackId), Track.class);
Optional<Track> track = tracksRepository.findById(trackId);
if (track.isPresent()) {
return new ResponseEntity<>(track.get(), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
with mongo config
#Configuration
#EnableMongoRepositories(basePackages = "data.store.repositories")
public class MongoConfig extends AbstractMongoClientConfiguration {
private final Logger LOGGER = Logger.getLogger(this.getClass().getSimpleName());
#Primary
#Bean
#Override
public MongoClient mongoClient() {
return MongoClients.create(MongoClientSettings.builder()
.applyToClusterSettings(builder -> builder.hosts(Arrays.asList(new ServerAddress(host, port))))
.build());
}
private MongoCredential mongoCredentials() {
return MongoCredential.createCredential(username, database, password.toCharArray());
}
#Bean
public MongoTemplate mongoTemplate() {
MongoTemplate mongoTemplate = new MongoTemplate(mongoClient(), getDatabaseName());
mongoTemplate.setReadPreference(ReadPreference.secondaryPreferred());
return mongoTemplate;
}
protected String getDatabaseName() {
return database;
}
#Override
public boolean autoIndexCreation() {
return false;
}
}
EDIT: Adding class for context
#Document("track")
public class Track {
#Id
#Field(ATTR_ID)
#JsonProperty(ATTR_ID)
public String id;
public static final String ATTR_ID = "id";
}
and getting always null, with existing keys on my database. could you help me find the issue?
Thanks in advance
I tried this with similar configuration class and found the following worked fine creating/accessing data using MongoTemplate.
The POJO class:
public class Test {
#MongoId(FieldType.OBJECT_ID)
private String id;
private String name;
public Test() {
}
public Test(String s) {
super();
this.name = s;
}
// get, set methods
public String toString( ) {
return id + " - " + name;
}
}
From Spring's CommandLineRunner.run():
// Insert a document into the database
Test t1 = new Test("alpha");
t1 = mt.insert(t1);
System.out.println(t1); // 61e7de9f5aadc2077d9f4a58 - alpha
// Query from the database using the _id
ObjectId id = new ObjectId("61e7de9f5aadc2077d9f4a58");
Test t2 = mt.findById(id, Test.class);
System.out.println(t2);
Note that you need to do this from the class where you are running the code:
#Autowired private MongoTemplate mt;
You can use the #MongoId or #Id annotations in our POJO class to represent MongoDB _id field. The type of the field can be a String or ObjectId. It depends upon how you define.
See this from Spring Data MongoDB documentation on How the _id Field is Handled in the Mapping Layer using:
#MongoId
#Id
Solution is to add to MongoId annotation field type object id
#MongoId(FieldType.OBJECT_ID)
private String id;

Spring EntityManager.persist issue

I am using a Spring framework (Boot+web+jpa) for a REST service and needs to persist an Entity called Sensor. Since I was using Hibernate, I wanted to keep usingEntityManager. From the Spring Data Access document and some of the questions answered in Stackoverflow, I could see that I should configure LocalEntityManagerFactoryBean or LocalContainerEntityManagerFactoryBean.
Now I was able to read persist.xml and persist the entity through dependency injection #PersistenceUnit(unitName="...") EntityManagerFactory in case for LocalContainerEntityManagerFactoryBean. However, Spring keeps throwing an error everytime when I try to persist new Sensor() instance with LocalEntityManagerFactoryBean as shown below.
// LocalEntityManagerFactoryBean
#Bean
public LocalEntityManagerFactoryBean entityManagerFactory() {
LocalEntityManagerFactoryBean em = new LocalEntityManagerFactoryBean();
em.setPersistenceUnitName("myunit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
Persisting (transaction.begin and end are in the caller method):
private Sensor getSensor(SimpleData sd) {
List<Sensor> sensors = entityManager.createQuery("select s from Sensor s where s.deviceId = :devid", Sensor.class)
.setParameter("devid", sd.getDeviceId())
.getResultList();
Sensor sensor = null;
if(sensors.isEmpty()) {
sensor = new Sensor();
sensor.setDeviceId(sd.getDeviceId());
sensor.setName(sd.getName());
entityManager.persist(sensor); // Throws an exception
deviceIdMapper.put(sensor.getDeviceId(), sensor.getId());
logger.trace("Cannot find the sensor in db, adding: "+sensor.getDeviceId());
} else {
sensor = sensors.get(0);
deviceIdMapper.put(sensor.getDeviceId(), sensor.getId());
logger.trace("Found a sensor from the db: "+sd.getDeviceId());
}
deviceIdMapper.putIfAbsent(sensor.getDeviceId(), sensor.getId());
logger.trace(sensor);
return sensor;
}
Exception:
javax.persistence.PersistenceException: org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [protected int com.database.Sensor.id] by reflection for persistent property [com.database.Sensor#id] : com.database.Sensor#6de9600a
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:807)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350)
at com.sun.proxy.$Proxy108.persist(Unknown Source)
at com.DataListener.getSensor(DataListener.java:69)
at com.DataListener.lambda$0(DataListener.java:87)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at com.DataListener.processData(DataListener.java:86)
at com.DataListener.onMessage(DataListener.java:49)
at org.apache.activemq.ActiveMQMessageConsumer.dispatch(ActiveMQMessageConsumer.java:1321)
at org.apache.activemq.ActiveMQSessionExecutor.dispatch(ActiveMQSessionExecutor.java:131)
at org.apache.activemq.ActiveMQSessionExecutor.iterate(ActiveMQSessionExecutor.java:202)
at org.apache.activemq.thread.PooledTaskRunner.runTask(PooledTaskRunner.java:129)
at org.apache.activemq.thread.PooledTaskRunner$1.run(PooledTaskRunner.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [protected int com.database.Sensor.id] by reflection for persistent property [com.database.Sensor#id] : com.database.Sensor#6de9600a
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:75)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:224)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4931)
at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4631)
at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:226)
at org.hibernate.event.internal.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:540)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:800)
... 20 more
Caused by: java.lang.IllegalArgumentException: Can not set int field com.database.Sensor.id to com.database.Sensor
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeIntegerFieldAccessorImpl.getInt(UnsafeIntegerFieldAccessorImpl.java:56)
at java.base/java.lang.reflect.Field.getInt(Field.java:594)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:62)
... 28 more
Sensor class:
#Entity
public class Sensor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected int id;
protected String deviceId;
protected String name;
#OneToMany(mappedBy = "owner", cascade=CascadeType.ALL)
private List<SimpleData> simpleDevices = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<SimpleData> getSimpleDevices() {
return simpleDevices;
}
public void setSimpleDevices(List<SimpleData> simpleDevices) {
this.simpleDevices = simpleDevices;
}
}
There are two questions:
Why the error?
Spring throws an error if I do not provide DataSource for LocalContainerEntityManagerFactoryBean? LocalEntityManagerFactoryBean uses DataSource configs from persistence.xml Why LocalContainerEntityManagerFactoryBean doesn't do the same?:
Edit 1
I think I have found a solution. If I remove spring-boot-devtools from the dependency, it fixes the problem. In fact when I use spring-boot-devtools I could not read Sensor due to some sort of ClassLoader problem. Maybe some sort of a bug?:
java.lang.ClassCastException: class com.database.Sensor cannot be cast to class com.database.Sensor (com.database.Sensor is in unnamed module of loader 'app'; com.database.Sensor is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader #6228d409)
Edit 2
Here is SimpleData class
#Entity
public class SimpleData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private double value;
#JsonIgnore
private Date time;
#Transient
private String deviceId;
#JsonIgnore
#Transient
private String name;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="sensor_id")
private Sensor owner;
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public Sensor getOwner() {
return owner;
}
public void setOwner(Sensor owner) {
this.owner = owner;
}
}
Edit 3
Okay, I made a small test program that reproduces the problem: https://github.com/hjparker/spring-boot-devtools-issue.
Once the server is up, you can make a GET request to localhost:8080, which will throw an error. Commenting out spring-boot-devtools in build.gradle will solve the problem. I found this is something to do with the restart classloader in spring-dev-tools (https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html), which reloads developing code every time spring is restarted. But I think some part of the file is not reloaded automatically causing the classcastexception, e.g. An entity loaded with CL1 != An entity loaded with CL2. Can someone explain if I am doing something wrong?
It seems some of the deserializers for Entity or Bean classes managed by hibernate/Spring ORM are not reloaded by the spring-boot-devtools restart classloader properly. I had to explicitly include the classes that perform deserialization to the restart classloader by setting the following properties in META-INF/spring-devtools.properties:
restart.include.hibernate=hibernate.*
restart.include.spring-orm=spring-orm.*
Sources:
https://github.com/AxonFramework/AxonFramework/issues/344
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html#using-boot-devtools-customizing-classload
Need to update access modifier private instead of protected, seems that Java persistence tries to get id which is not in package neither is called on some subclass.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String deviceId;
private String name;
Access modifier documentation

Hibernate: Program run persists new created entities together with entities which were persisted in previous program run and which I had deleted

This is maybe a beginner question on hibernate. I am doing my first steps, I designed a simple datamodel consisting of about 10 entities and I use hibernate to persist them to my Oracle XE database. Now I am facing the following problem: First time, when I do a transaction to persist some entities, they are persisted properly. I verify, that the data exists in the database and then I delete all the entries from all database tables. I verify that all tables are empty again. Then I run my program again to persist some new entities - and here happens something really strange: Afterwards I find in my databse the new entries as well as the old ones, which were persisted last time and which I had deleted! They contained the old IDs and the old data fields! How can this be? This happens even if I shut down my computer after the first time the program runs! How does it remember the old entries and where are they saved? Do you have any ideas?
Some information, that might be useful:
I am using annotations (instead of config files) for the mapping.
Following you see the classes used for persisting as well as one example of an entity (I am showing only one entity to avoid making the question too long).
As you see, I am using FetchType = EAGER on my MANY to MANY mappings (as I understand, this makes sure, that all related entities are loaded immediately together with any loaded entity). Can this have any impact?
Thanks for any help!
public class PersistenceManager {
private static final SessionFactory factory = new Configuration().configure().buildSessionFactory();
public static void sampleData() {
try(Session session = factory.openSession()) {
SampleDataLoader.loadSampleData(session);
} catch(HibernateException e) {
System.out.println("Exception during persisting! Message: " + e.getMessage());
e.printStackTrace();
}
}
}
public class SampleDataLoader {
static void loadSampleData(Session session) {
Language french = new Language("French");
Language german = new Language("German");
Noun garcon = new Noun(french, "garcon", false);
Noun junge = new Noun(german, "Junge", false);
junge.addTranslation(garcon);
ZUser user = new ZUser("Daniel", "password");
user.setOwnLanguage(german);
user.setEmail("abc#somemail.de");
user.setDateRegistered(LocalDateTime.now());
user.addForeignLanguage(french);
Transaction transaction = session.beginTransaction();
session.save(user);
session.save(french);
session.save(german);
session.save(junge);
transaction.commit();
}
}
#Entity
public class ZUser {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column
private String name;
#Column
private String password;
#Column
private String email;
#Column
private String picturePath;
#Column
private LocalDateTime dateRegistered;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="OWNLANGUAGE_ID")
private Language ownLanguage;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(name="USER_LANGUAGE",
joinColumns=#JoinColumn(name="USER_ID"),
inverseJoinColumns=#JoinColumn(name="LANGUAGE_ID")
)
private Set<Language> foreignLanguages = new HashSet<>();
public ZUser() { }
public ZUser(String n, String p) {
name = n;
password = p;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPicturePath() { return picturePath; }
public void setPicturePath(String picturePath) { this.picturePath = picturePath; }
public LocalDateTime getDateRegistered() { return dateRegistered; }
public void setDateRegistered(LocalDateTime dateRegistered) { this.dateRegistered = dateRegistered; }
public Language getOwnLanguage() { return ownLanguage; }
public void setOwnLanguage(Language ownLanguage) { this.ownLanguage = ownLanguage; }
public void addForeignLanguage(Language language) {foreignLanguages.add(language);}
public Set<Language> getForeignLanguages() {return Collections.unmodifiableSet(foreignLanguages); }
}
Clarified by the comment of Jagger (see comments). Indeed, I was using Oracle SQL command line to delete the entries and I had rgotten, that I need to explicitely commit after deleting. The solution can be so easy :)

Hibernate Lazy Load is Recursively Loading Set or Referencing data

I am having some strange issues with Hibenate lazy loading. I have 2 entities ProcessEntity and SectionEntity. A ProcessEntity can have many SectionEntity's and the SectionEntity should know which ProcessEntity it belongs to (#OneToMany). The problem I am having is when I load a ProcessEntity with hibernateTemplate.get(id) and then call my custom function fetchLazyCollections(entity, ...) which loops the entities methods until it finds a PersistentCollection and then forces a lazy load on that method.
When the ProcessEntity has its Set lazy loaded it recursively loads ALL the data in the SectionEntity meaning it loads the ProcessEntity which loads the SectionEntitys which load the ProcessEntity and so on! This causes a stack overflow when I try to serialize the data and must be terrible for performance. This doesn't happen when I make an HQL query etc.
Here is my setup for the Entities:
ProcessEntity:
#javax.persistence.Entity(name = "processes")
public class ProcessEntity extends Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id = Entity.UNSAVED_ID;
...
#OneToMany(fetch=FetchType.LAZY, mappedBy="process")
private Set<SectionEntity> sections = new HashSet<SectionEntity>();
...
public Set<SectionEntity> getSections() {
return sections;
}
public void setSections(Set<SectionEntity> sections) {
this.sections = sections;
}
...
}
SectionEntity:
#javax.persistence.Entity(name = "sections")
public class SectionEntity extends Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id = Entity.UNSAVED_ID;
...
#ManyToOne(fetch = FetchType.LAZY, targetEntity = ProcessEntity.class)
#JoinColumn(name="process", referencedColumnName="id")
private ProcessEntity process;
#Override
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
...
public ProcessEntity getProcess() {
return process;
}
public void setProcess(ProcessEntity process) {
this.process = process;
}
...
}
fetchLazyCollections:
public <E extends Entity> E fetchLazyCollections(E entity, String... specifiedCollections) {
if(getCurrentSession() == null) {
throw new SessionException("No session found for fetching collections.");
}
// Fetch the collections using reflection
Class<? extends Entity> clazz = entity.getClass();
for(Method method : clazz.getMethods()) {
Class<?> returnType = method.getReturnType();
if(ReflectUtils.isClassCollection(returnType)) {
// Check if the collection type is specified via the getter
List<String> specified = Arrays.asList(specifiedCollections);
if(!specified.isEmpty()) {
if(!specified.contains(method.getName())) {
continue;
}
}
try {
// Check that the collection is persistent
Collection collection = (Collection) method.invoke(entity);
if(collection instanceof PersistentCollection) {
collection.size(); // invokes lazy loading
}
}
catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
}
return entity;
}
I am using Spring on my back-end making use of #Transactional. Here is my Hibernate spring module (#Configuration):
#Configuration
#Import({
MappingModule.class
})
#ImportResource("classpath:nz/co/doltech/ims/properties.xml")
#EnableTransactionManagement
public class HibernateModule {
private static int statisticId = 0;
private #Value("#{app['root.path']}") String projectPath;
private #Value("#{app['database.jndiname']}") String databaseJndiName;
private #Value("#{app['hibernate.dialect']}") String hibernateDialect;
private #Value("#{app['hibernate.hbm2ddl']}") String hibernateHbm2dll;
private #Value("#{app['hibernate.show_sql']}") String hibernateShowSql;
private #Value("#{app['hibernate.format_sql']}") String hibernateFormatSql;
private #Value("#{app['hibernate.generate_statistics']}") String hibarnateStatistics;
private #Value("#{app['hibernate.cache.provider_class']}") String hibarnateCacheProviderClass;
private #Value("#{app['hibernate.cache.use_query_cache']}") String hibarnateQueryCache;
private #Value("#{app['hibernate.cache.use_second_level_cache']}") String hibarnateSecondLevelCache;
private #Value("#{app['hibernate.cache.use_structured_entries']}") String hibernateStructuredEntries;
private #Value("#{app['net.sf.ehcache.configurationResourceName']}") String hibernateEhcacheResource;
private #Value("#{app['flyway.enabled']}") String flywayEnabled;
private #Value("#{app['flyway.basePath']}") String flywayBasePath;
#Bean(name="dataSource")
public JndiObjectFactoryBean getDriverManagerDataSource() {
JndiObjectFactoryBean dataSource = new JndiObjectFactoryBean();
dataSource.setJndiName(databaseJndiName);
dataSource.setCache(true);
return dataSource;
}
#Bean(name="sessionFactory")
#DependsOn({"dataSource", "flyway"})
public AnnotationSessionFactoryBean getAnnotationSessionFactoryBean() {
AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean();
sessionFactory.setDataSource((DataSource) getDriverManagerDataSource().getObject());
sessionFactory.setPackagesToScan(new String[] {
projectPath + ".server.entities",
projectPath + ".server.entities.joins"
});
Properties props = new Properties();
props.setProperty("hibernate.dialect", hibernateDialect);
props.setProperty("hibernate.show_sql", hibernateShowSql);
props.setProperty("hibernate.hbm2ddl.auto", hibernateHbm2dll);
props.setProperty("hibernate.format_sql", hibernateFormatSql);
props.setProperty("hibernate.generate_statistics", hibarnateStatistics);
props.setProperty("hibernate.cache.provider_class", hibarnateCacheProviderClass);
props.setProperty("hibernate.cache.use_query_cache", hibarnateQueryCache);
props.setProperty("hibernate.hibernate.cache.provider_configuration_file_resource_path", hibernateEhcacheResource);
props.setProperty("hibernate.use_second_level_cache", hibarnateSecondLevelCache);
props.setProperty("hibernate.cache.use_structured_entries", hibernateStructuredEntries);
props.setProperty("javax.persistence.validation.mode", "none");
// caching resource
//props.setProperty("net.sf.ehcache.configurationResourceName", hibernateEhcacheResource);
//props.setProperty("hibernate.transaction.manager_lookup_class", "nz.co.doltech.ims.server.persistence.TransactionManagerLookup");
//props.setProperty("hibernate.transaction.factory_class", "org.hibernate.transaction.JTATransactionFactory");
sessionFactory.setHibernateProperties(props);
return sessionFactory;
}
#Bean(name="transactionManager")
#DependsOn("sessionFactory")
public HibernateTransactionManager getHibernateTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getAnnotationSessionFactoryBean().getObject());
return transactionManager;
}
#Bean(name="hibernateTemplate")
#DependsOn("sessionFactory")
public HibernateTemplate getHibernateTemplate() {
HibernateTemplate hibernateTemplate = new HibernateTemplate();
hibernateTemplate.setSessionFactory(getAnnotationSessionFactoryBean().getObject());
return hibernateTemplate;
}
#Bean(name="jmxExporter")
#DependsOn("hibernateStatisticsBean")
public MBeanExporter getJmxExporter() {
MBeanExporter exporter = new MBeanExporter();
Map<String, Object> map = new HashMap<>();
Properties props = AppProperties.getProperties();
String name = props.getProperty(AppProperties.CLIENT_MODULE_NAME);
String type = props.getProperty(AppProperties.CLIENT_RELEASE_STAGE);
map.put("Hibernate:"+name+"[" + ++statisticId + "]-"+type+"=Statistics",
getHibernateStatisticsBean());
exporter.setBeans(map);
return exporter;
}
#Bean(name="hibernateStatisticsBean")
public StatisticsService getHibernateStatisticsBean() {
StatisticsService statsBean = new StatisticsService();
statsBean.setStatisticsEnabled(true);
statsBean.setSessionFactory(getAnnotationSessionFactoryBean().getObject());
return statsBean;
}
#Bean(name="incidentDao")
#DependsOn("hibernateDao")
public IncidentHibernateDao getIncidentDao() {
IncidentHibernateDao incidentDao = new IncidentHibernateDao();
//incidentDao.registerBroadcasterId(AtmosphereConst.UPDATE_ID_KEY);
return incidentDao;
}
#Bean(name="transactionTemplate")
#DependsOn({"transactionManager"})
#Scope("prototype")
public TransactionTemplate getTransactionTemplate() {
return new TransactionTemplate(getHibernateTransactionManager());
}
}
This is the Hibernate output:
hibernateDao.get(...) called:
Hibernate: select processent0_.id as id27_0_, processent0_.description as descript2_27_0_, processent0_.name as name27_0_, processent0_.nametoken as nametoken27_0_, processent0_.order_value as order5_27_0_, processent0_.removed as removed27_0_ from processes processent0_ where processent0_.id=?
hibernateDao.fetchLazyCollections(...) called:
Hibernate: select incidentjo0_.process_id as process3_27_1_, incidentjo0_.incident_id as incident2_1_, incidentjo0_.process_id as process3_1_, incidentjo0_.incident_id as incident2_21_0_, incidentjo0_.process_id as process3_21_0_, incidentjo0_.completed as completed21_0_ from incident_process incidentjo0_ where incidentjo0_.process_id=?
Hibernate: select sections0_.process as process27_1_, sections0_.id as id1_, sections0_.id as id29_0_, sections0_.description as descript2_29_0_, sections0_.name as name29_0_, sections0_.order_value as order4_29_0_, sections0_.process as process29_0_, sections0_.removed as removed29_0_ from sections sections0_ where sections0_.process=?
Nothing else is called from that point.
Does anyone have any idea what is going on here? I am out of ideas.
Appreciate any help I can get!
Cheers,
Ben

Integrating JPA2.0 and Spring

last few hours I try to test with spring jpa 2.0 3.0
Finally I could recover objects persisted
but when I try to persist a new object I receive the following error message:
org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:306)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:102)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.orm.jpa.JpaAccessor.translateIfNecessary(JpaAccessor.java:152)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:188)
at org.springframework.orm.jpa.JpaTemplate.flush(JpaTemplate.java:288)
at myPackage.testDAO.create(testDAO.java:33)
at myPackage.Main.main(Main.java:27)
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:789)
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.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy21.flush(Unknown Source)
at org.springframework.orm.jpa.JpaTemplate$8.doInJpa(JpaTemplate.java:290)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:183)
... 3 more
my entity bean:
#Entity
public class Application implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="ID_APPLICATION")
private long idApplication;
#Temporal( TemporalType.DATE)
#Column(name="DATE_LIVRAISON")
private Date dateLivraison;
#Lob()
private String description;
#Column(name="NOM_APPLICATION")
private String nomApplication;
private String url;
//bi-directional many-to-one association to Test
#OneToMany(mappedBy="application")
private List<Test> tests;
public Application() {
}
public long getIdApplication() {
return this.idApplication;
}
public void setIdApplication(long idApplication) {
this.idApplication = idApplication;
}
public Date getDateLivraison() {
return this.dateLivraison;
}
public void setDateLivraison(Date dateLivraison) {
this.dateLivraison = dateLivraison;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getNomApplication() {
return this.nomApplication;
}
public void setNomApplication(String nomApplication) {
this.nomApplication = nomApplication;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public List<Test> getTests() {
return this.tests;
}
public void setTests(List<Test> tests) {
this.tests = tests;
}
}
my repository:
#Repository
public class testDAO extends JpaDaoSupport implements ItestDAO {
#PersistenceContext
private EntityManager em;
public List<Application> findALL() {
// TODO Auto-generated method stub
return null;
}
public Application findById(long id) {
// TODO Auto-generated method stub
return getJpaTemplate().find(Application.class, id);
}
public void create(Application application) {
getJpaTemplate().persist(application);
}
}
findById method works normally (which reassures me that jpa configuration is correct), but when I run the create method I receive the above error message.
ApplicationContext context=new ClassPathXmlApplicationContext("application-context.xml");
testDAO dao=(testDAO)context.getBean("dao");
Application application=new Application();
application.setIdApplication(2);
application.setUrl("url");
application.setDescription("description");
application.setNomApplication("dsdsds");
dao.create(application);
any help are appreciated
Thank you for your help
In short, methods of EntityManager such as persist, remove, merge must be called inside a transaction, hence the error message which is actually self explaining:
javax.persistence.TransactionRequiredException: no transaction is in progress
Spring provides support for transaction management (see links below), including when writing tests... if you use one of the Spring testing class providing transactional support.
See also
10. Transaction Management
10.5 Declarative transaction management
10.5.6 Using #Transactional

Categories