Here's the portion of our xml that is related to transaction management
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<tx:advice id="txAdvice"/>
<aop:config proxy-target-class="true">
<aop:pointcut id="transactionalMethods"
expression="#annotation(org.springframework.transaction.annotation.Transactional)" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionalMethods" />
</aop:config>
I came up with this
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement( proxyTargetClass = true )
public class TransactionConfig
{
#Bean
PlatformTransactionManager transactionManager( final DataSource dataSource, final EntityManagerFactory emf ) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource( dataSource );
jpaTransactionManager.setEntityManagerFactory( emf );
return jpaTransactionManager;
}
#Bean
PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}
}
and it seems to work, but reading the config I can't help but wonder if I'm supposed to use mode = ASPECTJ, but when I tried that the context blew up with an exception about not able to inject "Concrete class", as some things depend on the class and not the interface.
I'm not sure why we added that pointcut, or whether we make use of it, if I have to rewrite it as a pointcut, I'm actually not sure how I should do that.
Do I need to add something more to get parity? is this already the same? if I need to add more what should I write?
update
When trying
#Configuration
#EnableAspectJAutoProxy( proxyTargetClass = true )
#EnableTransactionManagement( mode = AdviceMode.ASPECTJ )
and aspectj itself was working via our xml config (the aspects do work in our xml config)
<context:spring-configured/>
<aop:aspectj-autoproxy/>
with deps
[INFO] +- org.springframework.data:spring-data-jpa:jar:1.9.4.RELEASE:compile
[INFO] | +- org.springframework:spring-orm:jar:4.2.7.RELEASE:compile
[INFO] | +- org.springframework:spring-context:jar:4.2.7.RELEASE:compile
[INFO] | | \- org.springframework:spring-expression:jar:4.2.7.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:4.2.7.RELEASE:compile
[INFO] | | \- aopalliance:aopalliance:jar:1.0:compile
[INFO] | +- org.springframework:spring-beans:jar:4.2.7.RELEASE:compile
[INFO] | +- org.springframework:spring-core:jar:4.2.7.RELEASE:compile
[INFO] | \- org.aspectj:aspectjrt:jar:1.8.9:compile
[INFO] +- org.springframework:spring-aspects:jar:4.2.7.RELEASE:compile
[INFO] +- org.aspectj:aspectjweaver:jar:1.8.9:compile
I get errors like
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.myapp.CatalogItemViewDao com.myapp.ProviderTestHistoryDao.catalogItemViewDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.CatalogItemViewDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 40 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.CatalogItemViewDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
No you dont need to set mode = ASPECTJ , unless you expect transaction to be applied on self invocation calls, means calling from another methods in the same class. Other mode proxy which default, will only support calls that coming externally through proxy interfaces.
In proxy mode (which is the default), only external method calls
coming in through the proxy are intercepted. This means that
self-invocation, in effect, a method within the target object calling
another method of the target object, will not lead to an actual
transaction at runtime even if the invoked method is marked with
#Transactional. Also, the proxy must be fully initialized to provide
the expected behaviour so you should not rely on this feature in your
initialization code,
if you set mode = aspectj , it will use spring AspectJ weaving using byte code modification for affected class and methods. But This will require spring-aspect.jar and CGLIB jars to be present in the class path.
And,
if you are just using #Transactional annotation you don't need define any aop point cuts. You only need to define the transaction manager
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative
If you use ASPECTJ (with spring-aspects-4.x.y.RELEASE.jar), a pointcut definition shouldn't be necessary.
Take a look at aop.xml in the mentioned jar, the AnnotationTransactionAspect is defined there.
Related
I am trying to upgrade my project to Spring 5.0.6 and Spring Data 2.0.6 and we are using WebSphere managed JPA 2.1
Getting below exception while creating the Spring context:
[5/29/18 6:30:41:929 CDT] 00000052 SystemOut O 06:30:41.876 [Default : 5] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mmm.arc.dao.UserRepository' available: expected at least 1 bean which qualifies as autowire candidate.
...
service class:
#Transactional(propagation = Propagation.REQUIRED )
public class UserServiceImpl implements UserService, UserDetailsService {
#PersistenceContext
private EntityManager em;
#Autowired
UserRepository userRepository;
}
repository class:
public interface UserRepository extends JpaRepository<User, String>, JpaSpecificationExecutor< User >,UserRepositoryCustom{
}
public class UserRepositoryImpl implements UserRepositoryCustom{
#PersistenceContext
EntityManager em;
-----------methods
}
in schema i have not mentioned any spring version
<jpa:repositories base-package="repo class package" /><bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistance unit name"/>
<property name="dataSource" ref="dataSource"/>
</bean>
we have separate persistence.xml file to map all entities which are completely annotation based
Your bean UserRepositoryImpl doesn't implement interface UserRepository, which is the type that UserServiceImpl is using. Thus, I think there actually is no UserRepository instance created anywhere.
Perhaps you intended for UserRepositoryImpl to implement UserRespository instead of UserRepositoryCustom?
I have spring boot application setup. Now I need to add Spring JDBC Template to it. While doing this, I am facing below exception.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'XXX': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.jdbc.core.JdbcTemplate com..XXX.jdbcTemplate; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (the profiles "LOCAL" are currently active).
Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (the profiles "LOCAL" are currently active).
Below is the code.
#Service
public class XXX {
#Autowired
JdbcTemplate jdbcTemplate;
public void testDataSource() {
List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from C_MASTER");
System.out.println("list : " + list);
}
}
Java Config
#Configuration
#ComponentScan
#EnableTransactionManagement
public class DAODataServiceManagerConfiguration {
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:#g9u1769.houston.hpecorp.net:1525:ODSDBD");
dataSource.setUsername("Solid_batch");
dataSource.setPassword("solid_batch123");
return dataSource;
}
}
As spring boot looks for application.properties, I have added that too in the resources directory.
appliation.properties.
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:#g9u1769.houston.hpecorp.net:1525:ODSDBD
spring.datasource.username=Solid_batch
spring.datasource.password=solid_batch123
spring.datasource.initialize=true
It is unable to build the application. Correct me if I am doing anything wrong.
You are missing ojdbc jar in your project classpath, follow below steps to download, install and use it as a dependency:
Download ojdbc6.jar from here.
Install it, running command -
mvn install:install-file -Dfile={Path/to/your/ojdbc.jar} -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0 -Dpackaging=jar
For jar version, extract the jar file and check the Implementation-Version in MANIFEST.MF, for instance:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 1.5.0_51-b10 (Sun Microsystems Inc.)
Implementation-Vendor: Oracle Corporation
Implementation-Title: JDBC
Implementation-Version: 11.2.0.4.0
Repository-Id: JAVAVM_11.2.0.4.0_LINUX.X64_RELEASE
Specification-Vendor: Sun Microsystems Inc.
Specification-Title: JDBC
Specification-Version: 4.0
Main-Class: oracle.jdbc.OracleDriver
sealed: true
Name: oracle/sql/converter/
Sealed: false
Name: oracle/sql/
Sealed: false
Name: oracle/sql/converter_xcharset/
Sealed: false
Name: oracle/replay/driver/
Sealed: false
Add as a dependency in the project, as follows:
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0</version>
</dependency>
Use jdbctemplate by extends JdbcDaoSupport .
By it programmer not concern about the open and close the connection.
Use commons-dbcp2-2.1.1.jar and commons-pool2-2.4.2.jar for use dbcp2 because dbcp2 support Connection pooling.
It's a technique to allow multiple clinets to make use of a cached set of shared and reusable connection objects providing access to a database
public class XXX extends JdbcDaoSupport {
public void testDataSource() {
List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from C_MASTER");
System.out.println("list : " + list);
}
}
In spring.xml write
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/database_name" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
<bean id="xXX" class="your_package_name.XXX">
<property name="dataSource" ref="dataSource" />
</bean>
I have gone through spring boot reference document. I came to know that if we are using (H2, HSQL or Derby) databases then we don't require application.properties.
If the project is having Oracle database, then application.properties should be updated. In my case I have updated the properties file.
So I have updated only following things, then it worked properly.
pom.xml
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
configuration file
#Configuration
public class DaoConfig {
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
dataSource.setUrl("xxx");
dataSource.setUsername("xxx");
dataSource.setPassword("xxx");
return dataSource;
}
#Bean
public JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(getDataSource());
}
I hope this might help someone.
Thanks #ChrisThompson and #Arpit
I have inherited an application that is written using Spring 3.2. The application works absolutely fine when built when it is not obfuscated. Once obfuscated (using ProGuard) I get the following exception in my logs.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mailStoreFactoryImpl': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [de.aeromaritime.messaging.roudistsrv.data.RdsDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#javax.annotation.Resource(mappedName=, shareable=true, description=, name=, type=class java.lang.Object, lookup=, authenticationType=CONTAINER)}
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:306)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1120)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at de.aeromaritime.messaging.roudistsrv.ServiceMain.main(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.rzo.yajsw.app.WrapperJVMMain.executeMain(WrapperJVMMain.java:53)
at org.rzo.yajsw.app.WrapperJVMMain.main(WrapperJVMMain.java:36)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [de.aeromaritime.messaging.roudistsrv.data.RdsDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#javax.annotation.Resource(mappedName=, shareable=true, description=, name=, type=class java.lang.Object, lookup=, authenticationType=CONTAINER)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:949)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:818)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:730)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 19 more
The thing is that the RdsDAO object is never made into a bean in the config.xml. This means it must be instanced by some other part of Spring. So I looked around and found that the PersistenceExceptionTranslationPostProcessor apparently loads objects that annotated with #Resource#Repository. So I checked the RdsDAO object and sure enough it has the correct annotation to be read.
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE, readOnly = true)
#Repository
public class RdsDAO implements Serializable
{ ...
}
Then I looked into the config.xml and find
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
<!-- ### enable annotations -->
<context:annotation-config/>
<!-- ### scan for annotations -->
<context:component-scan base-package="de.aeromaritime.messaging.roudistsrv"/>
<!-- ### AOP support -->
<!-- force use CGLIB to proxy classes even if there is an interface -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:spring-configured/>
<!-- Exception translation bean post processor -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- ### Create the PlatformTransactionManager -->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<!-- ### TX enable transaction annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
So the bean for PersistenceExceptionTranslationPostProcessor is there and should be working (as it does when the application is not obfuscated).
Finally I looked at the code for my mailStoreFactoryImpl bean which has the RdsDAO as a field like this:
public final class MailStoreFactoryImpl extends UnicastRemoteObject implements
ICMailStoreFactory, Serializable
{
#Resource
private RdsDAO rdsDAO;
...
}
Finally just to check, I decompiled my Jar file and looked at both the RdsDAO class, and MailStoreFactoryImpl class and found that they still have the same naming and contain the same fields, so basically Obfuscating didn't do anything to either of these classes. I'm beating my head on the desk trying to understand what Obfuscated did to break this application, but I'm at a loss. If anyone has any ideas I would love to hear from you.
[UPDATE]
I'm adding below the contents of my library.pro file:
#
# This ProGuard configuration file illustrates how to process a program
# library, such that it remains usable as a library.
# Usage:
# java -jar proguard.jar #library.pro
#
# Specify the input jars, output jars, and library jars.
# In this case, the input jar is the program library that we want to process.
-injars dist/ASYM_RDS-unobfuscated.jar
-outjars dist/ASYM_RDS.jar
-libraryjars <java.home>/lib/rt.jar
-libraryjars dist/lib
# Save the obfuscation mapping to a file, so we can de-obfuscate any stack
# traces later on. Keep a fixed source file attribute and all line number
# tables to get line numbers in the stack traces.
# You can comment this out if you're not interested in stack traces.
-printmapping out.map
#-keepparameternames
#-renamesourcefileattribute SourceFile
#-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
# SourceFile,LineNumberTable,EnclosingMethod
# Preserve all annotations.
-keepattributes *Annotation*
# Preserve all public classes, and their public and protected fields and
# methods.
-keep public class * {
# public protected *;
public *;
}
# Preserve all .class method names.
-keepclassmembernames class * {
java.lang.Class class$(java.lang.String);
java.lang.Class class$(java.lang.String, boolean);
}
# Preserve all public applications.
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}
# Preserve the special static methods that are required in all enumeration
# classes.
-keepclassmembers class * extends java.lang.Enum {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your library doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#Added as per answer to SO question http://stackoverflow.com/posts/25419369
-keepclassmembers class * {
#javax.annotation.Resource *;
}
# Your library may contain more items that need to be preserved;
# typically classes that are dynamically created using Class.forName:
# -keep public class mypackage.MyClass
# -keep public interface mypackage.MyInterface
# -keep public class * implements mypackage.MyInterface
-ignorewarnings
-dontoptimize
Try setting -keepclassmembers to #javax.annotation.Resource?
-keepclassmembers class * {
#javax.annotation.Resource *;
}
If that doesn't work, you might have to wire your context together by name, since your class names are likely getting mangled. Add #Bean("somename") to the classes and update the fields to #Resource("somename") so they match.
I'd like to make use of spring-data-jpa and CrudRepository<T, ID extends Serializable>. But I cannot get it autowired. (all other services in the same package are wired correctly):
#Service
public class UserService {
#Resource
private UserRepo repo;
//this does neither work
//#Autowired
//private CrudRepository<User, Long> repo;
}
public interface UserRepo extends CrudRepository<User, Long> {
}
#Entity
public class User {
#Id
private Long id;
}
Result:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'userService': Injection of resource
dependencies failed; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type [UserRepo] found for dependency: expected at
least 1 bean which qualifies as autowire candidate for this
dependency. Dependency annotations:
{#javax.annotation.Resource(shareable=true, mappedName=, description=,
name=, type=class java.lang.Object, lookup=,
authenticationType=CONTAINER)}
What might be wrong here?
From the docs I think it should work without writing an implementation:
In a typical Java application, you’d expect to write a class that
implements CustomerRepository. But that’s what makes Spring Data JPA
so powerful: You don’t have to write an implementation of the
repository interface. Spring Data JPA creates an implementation on the
fly when you run the application.
Updated SpringConfig:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories("my.package")
public class AppConfig {
#Bean
public LocalContainerEntityManagerFactoryBean emf() throws ClassNotFoundException, PropertyVetoException {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan("my.package");
emf.setJpaVendorAdapter(jpaAdapter());
emf.setJpaProperties(jpaProterties());
return emf;
}
}
Result: emf is missing, which is strange as I already have working DAO serices where I can autowire EntityManager and EMF without any problem.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#1a6e658': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' is defined
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:336)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:632)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:442)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:276)
... 50 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:641)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1159)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:282)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
... 58 more
You should verify the following:
1) Annotate the UserRepo with #Repository.
2) Your spring beans xml file should have in it:
<jpa:repositories base-package="your.repository.package"></jpa:repositories>
3) I'd recommend injecting this type of bean with #Autowired instead of #Resource
UPDATE
it seems you did my first 3 steps and you're one step ahead now. Now, remember that in Java Config methods names DO matter. Either change emf() to entityManagerFactory() (which is more "standard"), or set entity-manager-factory-ref to emf. Example:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException, PropertyVetoException {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan("my.package");
emf.setJpaVendorAdapter(jpaAdapter());
emf.setJpaProperties(jpaProterties());
return emf;
}
Doesn't UserRepo needs to be annotated with :
#Repository
It must be an issue in your applicationContext configuration. Here is the one I used to made it work:
<jpa:repositories
base-package="package.containing.your.repositories"
factory-class="org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean"
transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory" />
<bean
id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" />
<bean
id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<bean
id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"
p:persistenceUnitName="PU"
p:jpaVendorAdapter-ref="hibernateJpaVendorAdapter"
p:jpaProperties="classpath:hibernate.properties" />
<util:property-path id="sessionFactory" path="entityManagerFactory.sessionFactory" />
Configuring spring data JPA using XML and annotations
//This is the two way to configure spring data JPA
#EnableJpaRepositories (basePackages= "Repository Bean is located in package", entityManagerFactoryRef= "Here is your configuration of EntityManagerFactoryBean")
<jpa:repositories base-package= "Repository Bean where package"
Entity-manager-factory-ref= "Here is your configured EntityManagerFactoryBean" ></jpa:repositories>
// Sample code:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages="com.zxg.springdata",
entityManagerFactoryRef="factoryBean")
public class SpringDataConfig {
#Bean
public LocalContainerEntityManagerFactoryBean factoryBean (
ComboPooledDataSource dataSource, JpaVendorAdapter jpaVendorAdapter
){
LocalContainerEntityManagerFactoryBean factoryBean = new
LocalContainerEntityManagerFactoryBean ();
FactoryBean.setDataSource (dataSource);
FactoryBean.setJpaVendorAdapter (jpaVendorAdapter);
FactoryBean.setPackagesToScan ("com.zxg.springdata");
Return factoryBean;
}
}
I have been experimenting with using Spring 3.1's bean definition profiles and nested beans. I had hoped that I could define different beans depending on the active profile. Consider the following heavily over simplified example such that my Spring context contains something like
<bean id="say" class="test.Say" p:hello-ref="hello"/>
<beans profile="prod">
<bean id="hello" class="test.Hello" p:subject="Production!"/>
</beans>
<beans profile="dev">
<bean id="hello" class="test.Hello" p:subject="Development!"/>
</beans>
I get the following error:
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'say' defined in class path resource
[applicationContext.xml]: Cannot resolve reference to bean 'hello'
while setting bean property 'hello'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'hello' is defined at
org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
at
org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360)
aJava Result: 1
I was expecting that the hello bean would be defined according to the active Maven profile (in my case prod or dev). I'm starting to think that the Spring active profiles (spring.profiles.active) may be completely unrelated to Maven profiles.
Could somebody please explain where I am going wrong? (Is this even possible using profiles?).
I was expecting that the hello bean would be defined according to the active Maven profile (in my case prod or dev). I'm starting to think that the Spring active profiles (spring.profiles.active) may be completely unrelated to Maven profiles.
That's true, they are unrelated.
Here is how you can fix it:
Make sure that the web.xml that you have in src/main/webapp/WEB-INF/ folder has the following context setting:
<context-param>
<param-name>spring.profile.active</param-name>
<param-value>${profileName}</param-value>
</context-param>
And then make sure that the maven-war-plugin has filtering turned on for the web.xml:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
</plugin>
And then lastly in your profiles:
<profiles>
<profile>
<id>dev</id>
<properties>
<profileName>dev</profileName>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<profileName>prod</profileName>
</properties>
</profile>
</profiles>
You could also add a default value in the normal properties section:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<profileName>dev</profileName>
</properties>
So if you run without the -P option the dev spring profile will be used.
When running mvn package the web.xml will have the correct value for the spring.profile.active.
Thanks to maba (whose answer I shall accept), I started thinking about this in a different way.
I've modified the parent bean "say" because it needs to be lazily initialized because when it is initially encountered the nested bean contexts do not yet exist. So the new version adds a new bean and changes the "say" definition such that it now looks like:
<bean class="test.InitProfile" p:profiles="dev"/>
<bean id="say" class="test.Say" lazy-init="true" p:hello-ref="hello"/>
The new InitProfile bean is an InitializingBean responsible for setting up the active profiles.
It contains:
package test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;
public class InitProfile implements InitializingBean, ApplicationContextAware {
private ConfigurableApplicationContext ctx;
private String[] profiles;
public void setApplicationContext(ApplicationContext ac) throws BeansException {
ctx = (ConfigurableApplicationContext) ac;
}
public void setProfiles(String inprofiles) {
if (inprofiles.contains(",")) {
profiles = StringUtils.split(inprofiles, ",");
} else {
profiles = new String[]{inprofiles};
}
}
public void afterPropertiesSet() throws Exception {
String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
if (profiles != null && activeProfiles.length == 0) {
ctx.getEnvironment().setActiveProfiles(profiles);
ctx.refresh();
}
}
}
Using this approach has the added advantage of being able to set the active spring profile using a classpath properties file (this can differ depending on my active Maven profile). I also like this approach because I can use it for both web application and command line applications.