why jdk proxy could not be injected - spring

I use Aspect like this:
#Aspect
#Component
public class DataSourceAspect {
#Pointcut("#target(com.chen.dynamicsource.aspect.DataSource)")
public void pointCut() {
}
#Before("pointCut()")
public void doBefore(JoinPoint joinPoint) {}
}
And I add it to application.yml:
spring
aop:
proxy-target-class: false
When I run the application. I get the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'dispatcherServlet' could not be injected because it is a JDK dynamic proxy
The bean is of type 'com.sun.proxy.$Proxy67' and implements:
org.springframework.context.ApplicationContextAware
org.springframework.core.env.EnvironmentCapable
org.springframework.context.EnvironmentAware
javax.servlet.Servlet
javax.servlet.ServletConfig
java.io.Serializable
org.springframework.aop.SpringProxy
org.springframework.aop.framework.Advised
org.springframework.core.DecoratingProxy
Expected a bean of type 'org.springframework.web.servlet.DispatcherServlet' which implements:
I know I can use statically evaluated pointcut designators like within () and change the value of proxy-target-class to true to avoid the problem.
But I just want to know why jdk proxy could not be injected.

Related

#ConditionalOnBean not work for spring boot test

Hy everyone! I'm trying to solve the problem for a very long time.
There is very simple spring boot test
public class ApplicationTest {
#Test
void testContext() {
SpringApplication.run(Application.class);
}
}
And several beans...
#Service
#ConditionalOnBean(CommonService.class)
#RequiredArgsConstructor
public class SimpleHelper {
...
#Service
#RequiredArgsConstructor
#ConditionalOnBean(CommonFeignClient.class)
public class CommonService {
...
#FeignClient(
name = "CommonClient",
url = "localhost:8080"
)
public interface CommonFeignClient {
And the main class look as
#SpringBootApplication
#EnableFeignClients(clients = AnotherFeignClient.class)
public class Application {
When the spring application starts everything works ok. SimpleHelper does not created.
But in the spring boot test throw the exception:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'simpleHelper' defined in URL [...]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'foo.bar.CommonService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Please help, I don't understand what's going on anymore =)
Spring boot version is 2.3.0.RELEASE.
To use #ConditionalOnBean correctly, CommonService needs to be an auto-configuration class or defined as a bean by an auto-configured class rather than a service that's found by component scanning. This ensures that the bean on which CommonService is conditional has been defined before the condition is evaluated. The need for this is described in the annotation's javadoc:
The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.

DI in tests without using spring boot (#SpringBootTest)

Switching from spring boot back to "normal" spring because the app only uses some jdbc code to "upsert" into a postgresql database.
1)
tried annotating the test class with:
#RunWith(SpringJUnit4ClassRunner.class)
public class DBIntegration {
results in:
java.lang.IllegalStateException: Failed to load ApplicationContext
2)
tried annotating the class with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {})
public class DBIntegration {
[main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [de.mydomain.myproject.DBIntegration]: no resource found for suffixes {-context.xml}.
No exceptions, but java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=insertDataFrom_sometest],
3) tried annotating the class with:
#Component
public class DBIntegration {
dependency injection does not work in this case, the expected service
(to be injected) throws a nullpointerexception

Error creating bean with name 'batchConfigurer' in Spring Boot

I have a spring batch written using Spring boot. My batch only reads from MongoDB and prints the record.
I'm not using any SQL DB nor have any dependencies declared in project but While running it I'm getting below exception:
s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'batchConfigurer' defined in class path resource [org/springframework/boot/autoconfigure/batch/BatchConfigurerConfiguration$JdbcBatchConfiguration.class]: Unsatisfied dependency expressed through method 'batchConfigurer' parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-06-01 10:43:39.485 ERROR 15104 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of method batchConfigurer in org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration$JdbcBatchConfiguration required a bean of type 'javax.sql.DataSource' that could not be found.
- Bean method 'dataSource' not loaded because #ConditionalOnProperty (spring.datasource.jndi-name) did not find property 'jndi-name'
- Bean method 'dataSource' not loaded because #ConditionalOnClass did not find required class 'javax.transaction.TransactionManager'
Action:
Consider revisiting the conditions above or defining a bean of type 'javax.sql.DataSource' in your configuration.
In my pom.xml I've added below dependancies:
spring-boot-starter-batch
spring-boot-starter-data-mongodb
spring-boot-starter-test
spring-batch-test
Here's my batch configuration class:
#Configuration
#EnableBatchProcessing
public class BatchConfig {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private MongoTemplate mongoTemplate;
#Bean
public Job job() throws Exception {
return jobBuilderFactory.get("job1").flow(step1()).end().build();
}
#Bean
public Step step1() throws Exception {
return stepBuilderFactory.get("step1").<BasicDBObject, BasicDBObject>chunk(10).reader(reader())
.writer(writer()).build();
}
#Bean
public ItemReader<BasicDBObject> reader() {
MongoItemReader<BasicDBObject> reader = new MongoItemReader<BasicDBObject>();
reader.setTemplate(mongoTemplate);
reader.setCollection("test");
reader.setQuery("{'status':1}");
reader.setSort(new HashMap<String, Sort.Direction>() {
{
put("_id", Direction.ASC);
}
});
reader.setTargetType((Class<? extends BasicDBObject>) BasicDBObject.class);
return reader;
}
public ItemWriter<BasicDBObject> writer() {
MongoItemWriter<BasicDBObject> writer = new MongoItemWriter<BasicDBObject>();
return writer;
}
}
Here's is my launcher class:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
#SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyBatchApplication {
...
}
Spring Batch requires the use of a relational data store for the job repository. Spring Boot enforces that fact. In order to fix this, you'll need to add an in memory database or create your own BatchConfigurer that uses the Map based repository. For the record, the recommended approach is to add an in memory database (HSQLDB/H2/etc).

Spring - can't get simple aspect working

ERROR
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/callcentre] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: object is not an instance of declaring class
HandlerMethod details:
Controller [$Proxy109]
Method [public final java.lang.String au.com.mycompany.web.controllers.DummyControllerImpl.dummy()]
Resolved arguments:
] with root cause
java.lang.IllegalArgumentException: object is not an instance of declaring class
...
MAVEN DEPENDENCY
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.framework.version}</version>
</dependency>
SERVLET-CONTEXT.XML
<aop:aspectj-autoproxy />
ASPECT
#Aspect
#Component
public class JsonAspect {
#Before("execution(public * au.com.mycompany.web.controllers.DummyController.dummy(..))")
public final void beforeMethod1(final JoinPoint joinPoint) {
System.out.println("Intercepted.............");
System.out.println(joinPoint.getSignature().getName());
}
}
CONTROLLER INTERFACE
#Controller
public interface DummyController {
#RequestMapping(value = "/dummy", method = RequestMethod.GET)
#ResponseBody
String dummy();
}
CONTROLLER IMPL
#Controller
public class DummyControllerImpl implements DummyController {
#Override
public final String dummy() {
System.out.println("IT WORKED..........");
return "it returned";
}
}
I assume this is no longer relevant, but I had the exact same issue and the solution was to set this in the application context:
<aop:aspectj-autoproxy proxy-target-class="true"/>
Root cause, is that the AOP Auto Proxy generated for this class is a JdkAutoProxy instead of a CGLIB generated proxy - which causes a failure in the spring MVC invocation of the API since the proxy is not of the same type as the controller.
The reason for this JdkAutoProxy is since this specific controller implements an interface, which causes spring to automatically use the JDK auto proxy.

Proxy Exception while injecting spring bean into JSF bean

I'm trying to inject spring bean into JSF bean, I'm using Spring 3.1 and JSF 2 (Mojarra 2.1.7)
Without a lot of talking my configuration and code and exception listed in the following:
StudentService.java:
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
public class StudentsService extends AbstractMaqraaService {
#Override
public Set<Class<?>> getTypes() {
// TODO Auto-generated method stub
return null;
}
public Student registerStudent(Student student) {
return this.store(student);
}
}
StudentRegistrationMBean.java:
#ManagedBean(name="studentRegistrationMBean")
#SessionScoped
public class StudentRegistrationMBean extends AbstractMBean {
private Student student;
#ManagedProperty (value="#{studentsService}")
private StudentsService studentsService;
public StudentRegistrationMBean() {
this.student = new Student();
}
/*Setters and getters omitted here only*/
public String register() {
studentsService.registerStudent(student);
return "manageStudents";
}
}
Spring bean in module context xml file:
<bean id="abstractMaqraaService" class="org.tts.maqraa.service.AbstractMaqraaService" abstract="true"/>
<bean id="studentsService" class="org.tts.maqraa.service.StudentsService" lazy-init="default" parent="abstractMaqraaService"/>
faces-config.xml:
...
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
...
Eception:
TRACE [http-bio-8080-exec-3] (SpringBeanELResolver.java:53) - Successfully resolved variable 'studentsService' in Spring BeanFactory
DEBUG [http-bio-8080-exec-3] (AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'studentsService'
نوار 13, 2012 11:10:45 ص com.sun.faces.application.view.FaceletViewHandlingStrategy handleRenderException
SEVERE: Error Rendering View[/teacher/registerNewStudent.xhtml]
com.sun.faces.mgbean.ManagedBeanCreationException: Unable to set property studentsService for managed bean studentRegistrationMBean
at com.sun.faces.mgbean.ManagedBeanBuilder$BakedBeanProperty.set(ManagedBeanBuilder.java:615)
at com.sun.faces.mgbean.ManagedBeanBuilder.buildBean(ManagedBeanBuilder.java:133)
...
at java.lang.Thread.run(Unknown Source)
Caused by: javax.el.ELException: Cannot convert org.tts.maqraa.service.StudentsService#8f65bc0 of type class $Proxy10 to class org.tts.maqraa.service.StudentsService
at org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:420)
at org.apache.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:47)
at com.sun.faces.el.ELUtils.coerce(ELUtils.java:536)
at com.sun.faces.mgbean.BeanBuilder$Expression.evaluate(BeanBuilder.java:592)
at com.sun.faces.mgbean.ManagedBeanBuilder$BakedBeanProperty.set(ManagedBeanBuilder.java:606)
... 47 more
ERROR [http-bio-8080-exec-3] (MaqraaExceptionHandler.java:83) - Exception
javax.el.ELException: Cannot convert org.tts.maqraa.service.StudentsService#8f65bc0 of type class $Proxy10 to class org.tts.maqraa.service.StudentsService
at org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:420)
...
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I made a lot of search in Google and found a lot of questions here had issues like mine but nothing helped me, I hope I'll find my solution for my special case !!
use <aop:aspectj-autoproxy proxy-target-class="true"/> to enforce use of JDK proxy rather than CGLIB
if you inject your Spring service like this don't forget to create the setter for your Service:
#ManagedProperty (value="#{studentsService}")
private StudentsService studentsService;
public void setStudentsService (StudentsService studentsService)
{
this.studentsService = studentsService;
}
With the #Autowired annotation there was no need to do this.
Take a look at this answer It's about not using an interface for using your proxy.

Resources