Using ObjectDB with Spring Data JPA "com.objectdb.jpa.EMF is not an interface" - spring

Overflowers
I'm trying to get ObjectDB (2.7.6_01, latest) with Spring Data JPA (2.1.4, seemingly latest).
The docs for Spring Data JPA say that a version 2.1 JPA provider is needed. AFAIKT ObjectDB's JPA provider is 2.0 ... not sure if this is the problem or not.
But my problem is this exception:
Caused by: java.lang.IllegalArgumentException: com.objectdb.jpa.EMF is not an interface
Which is causing:
EntityManagerFactory interface [class com.objectdb.jpa.EMF] seems to conflict with Spring's EntityManagerFactoryInfo mixin - consider resetting the 'entityManagerFactoryInterface' property to plain [javax.persistence.EntityManagerFactory]
I'm happy that the ObjectDB entity manager factory is being picked properly by my code, but Spring's CGLIB wrapper around this class (EMF) is not working out.
Anyone got any ideas?
Gradle dependencies:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compile files('libs/objectdb-jee.jar')
compileOnly 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Then, either of these two #Beans (one or the other, not both) cause the same EMF exception above:
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
final ObjectdbJpaVendorAdapter vendorAdapter = new ObjectdbJpaVendorAdapter();
return vendorAdapter;
}
Or
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final ObjectdbJpaVendorAdapter vendorAdapter = new ObjectdbJpaVendorAdapter();
vendorAdapter.setShowSql(true);
vendorAdapter.setGenerateDdl(false);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.example.demo.persistence");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory;
}
I've got a no-op DataSource #Bean to keep some facet of Spring happy, but I don't think it's playing an active role in this problem.
No spring.jpa.* set at all.
Cheers

The Beans that you have to provide are much more simple:
#Bean
#ConfigurationProperties("app.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name="entityManagerFactory")
public EntityManagerFactory getEntityManagerFactoryBean() {
// this is the important part - here we use a local objectdb file
// but you can provide connection string to a remote objectdb server
// in the same way you create objectdb EntityManagerFactory not in Spring
return Persistence.createEntityManagerFactory("spring-data-jpa-test.odb");
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(emf);
return txManager;
}
With the above (and the proper dependencies in your pom.xml) there is no need for any additional configuration (i.e. no need for any configuration in application.properties).
A simple working example can be found here.

Related

spring boot with multiple databases

I'm trying to write an application that accesses data from two sources. I'm using Spring Boot 2.3.2. I've looked at several sources for info about how to configure the app: the Spring documentation talks about setting up multiple datasources, but does not explain how to link up JPA repositories. This Baeldung article goes a lot further, but I'm looking to take advantage of autoconfiguration in Spring.
So far, I've created a separate package, added a config class (along with model and repositories), and included this package in scanBasePackages so that it's picked up. Since I'll have more than one datasource, I've added this to my #SpringBootApplication:
#Bean
#Primary
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
This successfully loads up my Spring app using the standard spring config values. The two databases are on different servers, but should share characteristics (other than url and credentials).
So, my auxiliary configuration file looks like this
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "orgEntityManagerFactory",
transactionManagerRef = "orgTransactionManager",
basePackages = {
"pacage2.repositories"
}
)
public class DataSourceConfiguration {
// added because of this answer: https://stackoverflow.com/a/51305724/167889
#Bean
public EntityManagerFactoryBuilder entityManagerFactoryBuilder() {
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), new HashMap<>(), null);
}
#Bean
#ConfigurationProperties(prefix = "external.datasource")
public DataSourceProperties orgDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
public HikariDataSource orgDataSource(#Qualifier("orgDataSourceProperties") DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(HikariDataSource.class)
.build();
}
#Bean
public LocalContainerEntityManagerFactoryBean orgEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("orgDataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("package2.model")
.build();
}
#Bean
public PlatformTransactionManager orgTransactionManager(
#Qualifier("orgEntityManagerFactory") EntityManagerFactory entityManagerFactory
) {
return new JpaTransactionManager(entityManagerFactory);
}
}
Now, the error I'm getting right now is Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set. However, I have that value in my config and it's applied by the Spring auto config. I believe it needs to be set in the EntityManagerFactoryBuilder and by creating my own, the autoconfig isn't getting applied.
How can I have my cake and eat it too? I'd like to leverage as much of the robust autoconfiguration that Spring provides to setup datasources and wire them to the appropriate repositories. Effectively, all that I want to change is the url and credentials, and I can separate the entities and repositories into a completely separate package for easy scanning.

Spring boot with apache OpenJPA

I am trying to integrate my test spring boot application with DB.
I don't want to use Hibernate vendor, I want to use apache OpenJPA.
My current bootstrap.yml looks like this
spring:
datasource:
url: jdbc:oracle:thin:#xxxx:1521:xxx
username: xxxx
password: xxxx
driver-class-name: oracle.jdbc.OracleDriver
Is it possible to set dialect to work with OpenJPA?
Does spring supports today OpenJpa?
If you could provide some example of configuration it would be great.
Thank in advance.
upd: In example founded here - configure openjpa on to spring boot I see that used OpenJpaVendorAdapter which does not exist in spring 5.
In documentation of spring-data https://docs.spring.io/spring-data/jpa/docs/current/reference/html/ said that
Spring Data JPA 1.10 added the following features:
Upgrade to Querydsl 4, Hibernate 5, OpenJPA 2.4, and EclipseLink 2.6.1.
However I still don't see the proper way to configure it.
According to this page, You can not use Open Jpa with spring 5.
But this is an example for spring 4.
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
#EnableJpaRepositories(basePackages = "com.baoviet.mhol.persistence.dao")
#ComponentScan("com.baoviet.mhol.service")
public class JpaConfig {
#Bean(destroyMethod ="" )
public DataSource dataSource(#Value("${db.jndi}") String jndiName) {
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
lookup.setResourceRef(true);
return lookup.getDataSource(jndiName);
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.baoviet.mhol.persistence.model");
lef.setJpaDialect(new OpenJpaDialect());
return lef;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
OpenJpaVendorAdapter OpenJpaVendorAdaptor = new OpenJpaVendorAdapter();
OpenJpaVendorAdaptor.setShowSql(true);
OpenJpaVendorAdaptor.setGenerateDdl(true);
OpenJpaVendorAdaptor.setDatabasePlatform("org.OpenJpa.dialect.Oracle10gDialect");
return OpenJpaVendorAdaptor;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
}
Remember, in this case You do not need to persistence.xml file.
And This is Application.properties.
db.jndi=jdbc/batch
Note:
OpenJpa needs Persistence.xml to enhance entities at compile time.
So, You need to use different method for entity enhancement or provide your metadata in xml other than persistence.xml or use persistence.xml instead of data source.
You need to search for these more.
for entity enhancement solutions, please visit hear

Spring Boot 1.2.5.RELEASE & Spring Security 4.0.2.RELEASE - How to load configuration file before security context initialization?

I'm facing a problem with Spring: I'm migrating from Spring Security ver. 3.2.7.RELEASE to 4.0.2.RELEASE. Everything was working fine in older version, however a problem occured when it came to loading DataSource.
Let me describe the architecture:
Application is secured with both SAML and LDAP mechanisms (SAML configuration is pretty similar to config given here: https://github.com/vdenotaris/spring-boot-security-saml-sample/blob/master/src/main/java/com/vdenotaris/spring/boot/security/saml/web/config/WebSecurityConfig.java).
They both need to connect to database in order to get some required data. We use MyBatis with Spring Mybatis to get needed data. That's, where the problem begins.
My DAO configuration class looks like this:
#Configuration
#EnableConfigurationProperties
#MapperScan(basePackages = { "pl.myapp" })
public class DaoConfiguration {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
#Bean
#Primary
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
// some stuff happens here
return sqlSessionFactoryBean;
}
#Bean
#Primary
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
#ConfigurationProperties(prefix = "liquibase.datasource")
#ConditionalOnProperty(name="liquibase.enabled")
public DataSource liquibaseDataSource() {
DataSource liquiDataSource = DataSourceBuilder.create().build();
return liquiDataSource;
}
}
In previous version it worked like a charm, but now it has a problem loading mappers, resulting in Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someMapper' defined in file [<filename>]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
over and over again (it's not my problem, it's a known Spring/MyBatis bug).
I did some debugging and discovered something interesting: it looks like DaoConfiguration is not treated like a configuration here! I mean: if I add
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
return sqlSessionFactoryBean().getObject();
}
to this config, "normal" call of #Bean annotated method should result in calling proper interceptor, here it lacks this funcionality.
My prediction is that: this config class has not been properly wrapped yet and Spring Security already needs beans produced by it.
Is there any solution to properly load this configuration before Spring Security is initialized? Or am I just wrong and missing something (maybe not so) obvious?

How to define HSQ DB properties in Spring JPA using annoations

I am running HSQL DB as a Im memory using run manger Swing.I have to connect the HSQLDB server from Spring JPA repository using annotations.
My repository class.
#RepositoryRestResource
public interface Vehicle extends JpaRepository<Vehicle , BigInteger>{
public List<Vehicle > findAll(Sort sort);
}
service Method:
#Service
public class LocationService {
#Autowired
VehicletRepository vehicleRepository = null;
/**
* This method is to get all the locations from the repository
*/
public List<Vehicle> getVehicless() {
Order order = new Order(Direction.ASC,"vehicleCode");
Sort sort = new Sort(order);
List<Airport> airports = vehicletRepository .findAll(sort);
System.out.println("inside service");
return vehicles;
}
}
Anyone help to achieve Spring JPA conenction with HSQL DB using annotations.
I assume you dont use Spring boot:
you need #Configuration class -(it basically is new way to configure spring applications in java ) with #EnableJpaRepositories which turn it spring data jpa/ spring data rest for you. You will also have to specify your entity manager, transaction manager and data source beans. Example below:
#Configuration
#EnableJpaRepositories("your.package.with.repositories")
public class DBConfig{
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
DBConfigurationCommon.configureDB(dataSource, your_jdbc_url_here, db_username_here, db_password_here);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
//you may need to define new Properties(); here with hibernate dialect and add it to entity manager factory
entityManagerFactoryBean.setPackagesToScan("your_package_with_domain_classes_here");
return entityManagerFactoryBean;
}
}

Is there a way to define a default transaction manager in Spring

I have an existing application that uses the Hibernate SessionFactory for one database. We are adding another database for doing analytics. The transactions will never cross so I don't need JTA, but I do want to use JPA EntityManager for the new database.
I've set up the EntityManager and the new transaction manager, which I've qualified, but Spring complains that I need to qualify my existing #Transactional annotations. I'm trying to find a way to tell Spring to use the txManager one as the default. Is there any way of doing this? Otherwise I'll have to add the qualifier to all the existing #Transactional annotations which I would like to avoid if possible.
#Bean(name = "jpaTx")
public PlatformTransactionManager transactionManagerJPA() throws NamingException {
JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
return txManager;
}
#Bean
public PlatformTransactionManager txManager() throws Exception {
HibernateTransactionManager txManager = new HibernateTransactionManager(sessionFactory());
txManager.setNestedTransactionAllowed(true);
return txManager;
}
Error I'm getting
No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2:
Thanks
I was able to solve this using the #Primary annotation
#Bean(name = "jpaTx")
public PlatformTransactionManager transactionManagerJPA() throws NamingException {
JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
return txManager;
}
#Bean
#Primary
public PlatformTransactionManager txManager() throws Exception {
HibernateTransactionManager txManager = new HibernateTransactionManager(sessionFactory());
txManager.setNestedTransactionAllowed(true);
return txManager;
}
Since the same type of bean is produced from two methods, you must qualify the #Transactional annotation with the named bean. An easy way around to suite your need will be to use two different Spring application contexts. One operating with the old data source and one operating with new. Each of these contexts will have only one method producing the PlatformTransactionManager instance.

Resources