Adding AspectJ to existing project - spring

I am using spring-security project to try out OAuth2 server implementation. I have cloned the git project from https://github.com/SpringSource/spring-security-oauth.
The example is working as documented. Now to trace the flow, I want to add function entry/exit using AOP to existing code. For this I have done following changes:
Added a class "Watcher.java" (code below)
Added AspectJ dependencies in pom.xml
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.3</version>
</dependency>
Project builds and runs
But do not see the AspectJ markers for each function
Is it possible to add function entry/exit logging with this method without changing much of the original code?
Watcher.java:
package org.springframework.security.oauth.examples.sparklr;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
#Aspect
public class Watcher {
#Pointcut("execution(* *(..))")
public void watch() {
}
#Before("watch()")
public void preWatch(JoinPoint joinPoint) {
if (joinPoint.getArgs().length > 0) {
String[] args = new String[joinPoint.getArgs().length];
System.arraycopy(joinPoint.getArgs(), 0, args, 0,
joinPoint.getArgs().length);
System.out.println("-> " + joinPoint.toShortString()
+ Arrays.toString(joinPoint.getArgs()));
} else {
System.out.println("-> " + joinPoint.toShortString());
}
System.out.println("Args: " + joinPoint.getArgs().length);
}
#AfterReturning("watch()")
public void postWatch(JoinPoint joinPoint) {
System.out.println("<- " + joinPoint.toShortString());
}
}

You should enable AspectJ in spring configuration (to scan automagically your annotations)
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
xmlns:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="..."/>
<aop:aspectj-autoproxy />
...
</beans>
Maybe you will nedd to the spring-aop dependency to your project too.

Related

Autowired applicationContext is null in JUnit 5

I'm trying to migrate my spring applications to test with JUnit 5. It worked fine with JUnit 4. My problem is that I can't access the application context, it is null, but should be an object. I've included imports etc, in case something is wrong there.
Test:
package com.mycompany.mavenspringjunit5;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
#SpringJUnitConfig(locations = "/test-config.xml")
public class MainTest
{
#Autowired
ApplicationContext applicationContext;
#Autowired
Integer number;
// fails
#Test
public void testGivenAppContext_WhenInjected_ThenItShouldNotBeNull()
{
System.out.println("number: " + number);
Assertions.assertNotNull(applicationContext, "applicationContext should not be null");
}
// works
#Test
public void testDoStuff()
{
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/test-config.xml");
Main instance = ctx.getBean(Main.class);
instance.doStuff();
}
}
Main:
package com.mycompany.mavenspringjunit5;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class Main
{
#Autowired
Integer number;
#Autowired
ApplicationContext applicationContext;
public static void main(String[] args)
{
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.getBean(Main.class).doStuff();
}
void doStuff()
{
System.out.println("The number is " + number);
System.out.println("applicationContext " + applicationContext);
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>MavenSpringJunit5</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.3.4</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
test-config.xml (in the directory "....\MavenSpringJunit5\src\test\resources\test-config.xml"):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:annotation-config />
<context:component-scan base-package="com.mycompany.mavenspringjunit5"/>
<bean id="number" class="java.lang.Integer">
<constructor-arg value="42" />
</bean>
</beans>
Output:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.mycompany.mavenspringjunit5.MainTest
The number is 42
applicationContext org.springframework.context.support.ClassPathXmlApplicationContext#51521cc1, started on Mon Feb 22 10:49:15 CET 2021
number: null
Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.884 sec <<< FAILURE!
com.mycompany.mavenspringjunit5.MainTest.testGivenAppContext_WhenInjected_ThenItShouldNotBeNull() Time elapsed: 0.009 sec <<< FAILURE!
org.opentest4j.AssertionFailedError: applicationContext should not be null ==> expected: not <null>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:39)
at org.junit.jupiter.api.Assertions.fail(Assertions.java:118)
at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:47)
at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:36)
at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:292)
at com.mycompany.mavenspringjunit5.MainTest.testGivenAppContext_WhenInjected_ThenItShouldNotBeNull(MainTest.java:24)
Tested it and tests run fine in my IDE (Intellij) running the same with your provided pom.xml fails.
You need to upgrade the maven-surefire-plugin to properly detect and execute the classes.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
This is also expressed in the Junit5 documentation.

AspectJ LTW not getting configured with Spring in Tomcat

I have followed the steps given in the following spring docs:
https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/html/aop.html#aop-aj-ltw
My project is a monolith with modules as such :
ApplicationService in module m1.
Child module m2 with parent m1.(m1 has a dependency on m2)
aop.xml file in m1/WebContent/META-INF/aop.xml as follows :
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="m2.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="m2.security.FieldPermissionAspect"/>
</aspects>
Application-context.xml file in m1/src/main/webapp/WEB-INF as follows :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
...
<mvc:annotation-driven />
<aop:aspectj-autoproxy />
<task:annotation-driven />
<!-- this switches on the load-time weaving -->
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver"/>
My aspect in m2.security is as follows:
package m2.security;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class FieldPermissionAspect {
#Pointcut("execution(public * *(..))")
public void combinedPointcut() {}
#Around("combinedPointcut()")
public void aroundMapper(ProceedingJoinPoint joinPoint) {
...
}
#Around("cflow(combinedPointcut())")
public void aroundSetter(ProceedingJoinPoint joinPoint) {
...
}
}
AspectJ dependencies in pom.xml in m2:
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.7</version>
</dependency>
</dependencies>
When I run it in tomcat environment, I get the following error :
Caused by: org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException: Pointcut expression 'cflow(combinedPointcut())' contains unsupported pointcut primitive 'cflow'
at org.aspectj.weaver.tools.PointcutParser.validateAgainstSupportedPrimitives(PointcutParser.java:425)
at org.aspectj.weaver.tools.PointcutParser.resolvePointcutExpression(PointcutParser.java:311)
at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:294)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:207)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:193)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:170)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:208)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:262)
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:294)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:118)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:88)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:330)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1577)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 66 more
I think it's because spring is still using Spring AOP instead of AspectJ in my aspect. What am I missing here?
If you want to use AspectJ LTW instead of Spring AOP, you should not use Spring AOP configuration. so please get rid of <aop:aspectj-autoproxy />. Despite the name it is about Spring AOP, not AspectJ. AspectJ does not use any proxies.
As for your error message, ...
Caused by: org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException:
Pointcut expression 'cflow(combinedPointcut())'
contains unsupported pointcut primitive 'cflow'
... it occurs because you are still using Spring AOP, AspectJ LTW is not used. So you are having a configuration issue. Does it work if you start your container with
-javaagent:/path/to/aspectjweaver.jar
on the Java command line?
Last, but not least, like I said 3x already in your previous question, please provide an MCVE on GitHub, then I can analyse your problem. I really cannot do more than speculate with the bits of information provided by you here. So please do what I asked you to and help me to help you. Thanks.

How to configure Spring Repository to use mongoTemplate defined in xml bean?

The code executes fine, but creates collections in default mongo database and location i.e in test database # localhost:27017. In the mongoTemplate bean wired through the below xml, I'm using mydb as database with mongod instance running at localhost:27018. However, the data still gets persisted to default instance and database.
MongoDB XML Bean defined in src/main/resources/mongo-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
<mongo:mongo id="mongo" host="localhost" port="27018"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<constructor-arg value="mydb" />
</bean>
<mongo:repositories base-package="core.repository" mongo-template-ref="mongoTemplate"/>
</beans>
Playlist repository:
package core.repository;
import core.dao.Playlist;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.repository.Repository;
/**
* This repository provides CRUD operations for {#link core.dao.Playlist} objects.
*/
public interface PlaylistRepository extends Repository<Playlist, String> {
/**
* Finds the information of a single Playlist entry.
* #param id The id of the requested Playlist entry.
* #return The information of the found Playlist entry. If no Playlist entry
* is found, this method returns an empty {#link java.util.Optional} object.
*/
Optional<Playlist> findOne(String id);
/**
* Saves a new Playlist entry to the database.
* #param saved The information of the saved Playlist entry.
* #return The information of the saved Playlist entry.
*/
Playlist save(Playlist saved);
}
Playlist service that uses repository:
package core.service;
import core.dao.*;
import core.error.NotFoundException;
import core.repository.PlaylistRepository;
import core.simulator.PlaylistServiceSimulator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Executes the business logic promised by the {#link core.service.PlaylistService} interface.
*/
#Service
final class PlaylistServiceExecutor implements PlaylistService {
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistServiceExecutor.class);
private final PlaylistRepository repository;
private final PlaylistServiceSimulator simulator;
#Autowired
PlaylistServiceExecutor(PlaylistRepository repository, PlaylistServiceSimulator simulator) {
this.repository = repository;
this.simulator = simulator;
}
#Override
public PlaylistDTO create(PlaylistDTO playlist) {
LOGGER.debug("Creating a new Playlist entry with information: {}", playlist);
Playlist persisted = Playlist.build()
persisted = repository.save(persisted);
LOGGER.debug("Created a new Playlist entry with information: {}", persisted);
return persisted.toDTO();
}
#Override
public PlaylistDTO findById(String id) {
LOGGER.debug("Finding Playlist entry with id: {}", id);
Playlist found = findPlaylistById(id);
LOGGER.debug("Found Playlist entry: {}", found);
return found.toDTO();
}
private Playlist findPlaylistById(String id) {
Optional<Playlist> result = repository.findOne(id);
return result.orElseThrow(() -> new NotFoundException(id));
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>myapp</groupId>
<artifactId>core</artifactId>
<version>0.1</version>
<properties>
<!-- Enable Java 8 -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Configure the main class of our Spring Boot application -->
<start-class>core.CoreApp</start-class>
</properties>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.9.RELEASE</version>
</parent>
<dependencies>
<!-- Get the dependencies of a web application -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!-- Spring Data MongoDB-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot Maven Support -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Finally, SpringApplication boot class CoreApp:
package core;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* This configuration class has three responsibilities:
* <ol>
* <li>It enables the auto configuration of the Spring application context.</li>
* <li>
* It ensures that Spring looks for other components (controllers, services, and repositories) from the
* <code>core</code> package.
* </li>
* <li>It launches our application in the main() method.</li>
* </ol>
*/
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class CoreApp {
public static void main(String[] args) {
SpringApplication.run(CoreApp.class, args);
}
}
I'm assuming you're using Spring boot for it's auto configuration features and opinionated defaults. If so, you should let Spring configure your Mongo repository.
Remove your mongo configuration in src/main/resources/mongo-context.xml
Replace the mongo dependency
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
with the following Spring boot dependency to pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
Make sure your repositories extend MongoRepository
Have at least the following properties in your application.properties. See Spring Boot appendix for properties reference
spring.data.mongodb.uri=mongodb://localhost:27018/mydb
spring.data.mongo.repositories.enabled=true
Here are some additional guides:
https://spring.io/guides/gs/accessing-data-mongodb/
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-nosql.html
You can use applicationContext.xml file for this. It looks like below:
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:security="http://www.springframework.org/schema/security" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
<description><![CDATA[
Main entry point for spring configuration
]]></description>
<!-- Connection to MongoDB server -->
<mongo:db-factory host="localhost" port="27017" dbname="test" />
<!-- MongoDB Template -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
</bean>
<!-- Package w/ automagic repositories -->
<mongo:repositories base-package="com.bedas.ays.mongo" />
</beans>

Spring #Autowired working without context:annotation-config [duplicate]

This question already has answers here:
Difference between <context:annotation-config> and <context:component-scan>
(15 answers)
Closed 3 years ago.
I've tested the behavior of auto wiring in case the context:annotation-config element is missing in the application context xml file. To my surprise it worked just the same.
So here is my question:
How come an AutowiredAnnotationBeanPostProcessor is registered in the ApplicationContext even though the context:annotation-config element is missing from the application context configuration file, or what else mechanism makes this configuration work?
I'm using Spring version 3.0.6.RELEASE
This is the project pom file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven- v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples.spring</groupId>
<artifactId>spring-utility</artifactId>
<version>1.0.0.CI-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring Utility</name>
<url>http://www.springframework.org</url>
<description>
<![CDATA[
This project is a minimal jar utility with Spring configuration.
]]>
</description>
<properties>
<maven.test.failure.ignore>true</maven.test.failure.ignore>
<spring.framework.version>3.0.6.RELEASE</spring.framework.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
This is the application context configuration file, with the context:annotation-config element commented out:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<description>Example configuration to get you started.</description>
<!-- context:annotation-config/ -->
<context:component-scan base-package="com.foo.ch04" />
</beans>
A MessageProvider, that will be used as collaborator by a dependent bean MessageRenderer
package com.foo.ch04.helloworld;
import org.springframework.stereotype.Service;
#Service("messageProvider")
public class HelloWorldMessageProvider implements MessageProvider {
public String getMessage() {
return "Hello, World!";
}
}
The MessageRenderer, whose dependency messageProvider gets auto-injected:
package com.foo.ch04.helloworld;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service("messageRenderer")
public class StandardOutMessageRenderer implements MessageRenderer {
private MessageProvider messageProvider;
public void render() {
if (messageProvider == null) {
throw new RuntimeException(
"You must set the property messageProvider before rendering message.");
}
System.out.println(messageProvider.getMessage());
}
#Autowired
public void setMessageProvider(MessageProvider provider) {
messageProvider = provider;
}
public MessageProvider getMessageProvider() {
return messageProvider;
}
}
The test application loading the application context and testing the messageRenderer:
package com.foo.ch04.helloworld;
import org.springframework.context.support.GenericXmlApplicationContext;
public class DeclareSpringComponents {
public static void main(String[] args) {
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("classpath:META-INF/spring/app-context-annotation.xml");
context.refresh();
MessageRenderer renderer = context.getBean("messageRenderer",
MessageRenderer.class);
renderer.render();
}
}
Even though the is missing in the application context configuration file, the message "Hello, World!" is written to stdout when the application is run.
The use of <context:component-scan /> implies annotation based configuration and as such specifying <context:annotation-config/> is redundant.
'context:annotation-config' This annotation-config tag is used to process the auto wired beans declared in the application context XML file. If the auto wired bean could be discovered using the scope of 'context:component-scan' tag then no need to use 'context:annotation-config' tag

MongoTemplate instance is not created inside spring

I want to try spring integration with MongoDB, For this purpose I did following things. but its not working Some how MongoTemplate instance is not created and throws java.lang.NullPointerException.
here is my application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Activate annotation configured components -->
<context:annotation-config/>
<!-- Scan components for annotations within the configured package -->
<context:component-scan base-package="com.jeroenreijn.mongodb.example">
<context:exclude-filter type="annotation" expression="org.springframework.context.annotation.Configuration"/>
</context:component-scan>
<!-- Factory bean that creates the Mongo instance -->
<bean id="mongo" class="com.mongodb.Mongo">
<constructor-arg name="host" value="127.0.0.1" />
<constructor-arg name="port" value="27017" />
</bean>
<!-- Define the MongoTemplate which handles connectivity with MongoDB -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate" depends-on="mongo">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="databaseName" value="firstMongoDB"/>
</bean>
<!-- Use this post processor to translate any MongoExceptions thrown in #Repository annotated classes -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
here is my main method :
public class MainApplication {
/**
* This is a variable used for Logging purpose, I have used slf4j.
*/
final Logger LOGGER = LoggerFactory.getLogger(MainApplication.class);
#Autowired
MongoTemplate mongoTemplate;
public void savePerson(Person p) {
mongoTemplate.save(p);
}
public static void main(String[] args) {
Person p = new PersonImpl("1", "Ayushya", "Devmurari");
MainApplication ma = new MainApplication();
ma.savePerson(p);
ma.LOGGER.info("Person named : " + p.getName() + " with id : "
+ p.getId() + " is saved.");
}
}
Here is my model class :
#Document(collection = "AnotherPersonCollection")
public class PersonImpl implements Person {
private String id;
private String name;
private String surname;
// Constructor
public PersonImpl() {
}
public PersonImpl(String id, String name, String surname) {
this.id = id;
this.name = name;
this.surname = surname;
}
#Override
public String getId() {
return id;
}
#Override
public void setId(String id) {
this.id = id;
}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
#Override
public String getSurname() {
return surname;
}
#Override
public void setSurname(String surname) {
this.surname = surname;
}
#Override
public String toString() {
return "Person has name " + "Id :" + id + "\n" + name + " \n"
+ "surname :" + surname;
}
}
Need assistance I have tried several tutorials, like mkyong and many others and I have faced NoBeanDefinitionFound for "mongoTemplate" error: so I tried this.
UPDATE: here is my pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.discusit</groupId>
<artifactId>MongoDBAppTrail4</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>Trying to create MongoDBApp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- Log4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<!-- mongodb java driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>2.11.0</version>
</dependency>
<!-- Spring data mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Here is my stacktrace :
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mongoTemplate' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:568)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1102)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1117)
at com.discusit.main.MainApplication.main(MainApplication.java:39)
I have look #Aayush solution. I have found two errors:
You don't call correctly your xml file configuration.
Before:
ApplicationContext ctx = new GenericXmlApplicationContext("classpath*:application-context.xml");
After:
ApplicationContext ctx = new GenericXmlApplicationContext("classpath:META-INF/applicationContext.xml");
You call an ExceptionTranslationPostProcessor. Why ? This call causes an error. I removed it.
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
So finally, i have tested your application with small changes and all it's working. Dont forget to start mongodb server and create your database "firstMongoDB". For more information read here: http://docs.mongodb.org/manual/tutorial/getting-started/
I have published your project in github: https://github.com/m-reka/spring-data-mongoTemplate
Tell me when i can remove it :)
As mentioned, you have to create application context in your main class. To use autowire you can define your main class as spring bean.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- your mongodb bean befinitions -->
<bean class="fullpackage.MainApplication"/>
</beans>
And then just get the instance in your main class
public class MainApplication {
/**
* This is a variable used for Logging purpose, I have used slf4j.
*/
final Logger LOGGER = LoggerFactory.getLogger(MainApplication.class);
#Autowired
MongoTemplate mongoTemplate;
public void savePerson(Person p) {
mongoTemplate.save(p);
}
public static void main(String[] args) {
ApplicationContext ctx = new GenericXmlApplicationContext("application-context.xml");
MainApplication ma = ctx.getBean(MainApplication.class);
Person p = new PersonImpl("1", "Ayushya", "Devmurari");
ma.savePerson(p);
ma.LOGGER.info("Person named : " + p.getName() + " with id : " + p.getId() + " is saved.");
}
}
in your main method add :
ApplicationContext context =
new ClassPathXmlApplicationContext("application-context.xml"); //change xml path as you need.
MMongoTemplate mongoTemplate=context.getBean(MMongoTemplate.class);
As you use main method, which is skipping loading the beans in spring context , so the autowire will not work.
use this way to configure mongodb
AppMongoConfig.class
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import com.mongodb.Mongo;
#Configuration
public class AppMongoConfig {
public #Bean
MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new Mongo(), "testing");
}
public #Bean
MongoTemplate mongoTemplate() throws Exception {
//remove _class
MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
converter.setTypeMapper(new DefaultMongoTypeMapper(null));
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);
return mongoTemplate;
}
}
/-------------------------------------------------------------------------------------------------/
testing-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<mongo:mongo host="testing" port="27017">
<mongo:options connections-per-host="100"
threads-allowed-to-block-for-connection-multiplier="5"
max-wait-time="120000000"
connect-timeout="10000000"
socket-keep-alive="true"
socket-timeout="15000000"
auto-connect-retry="true"/>
</mongo:mongo>
<mongo:db-factory dbname="testing"
mongo-ref="mongo" />
<bean id="mongoTypeMapper"
class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
<constructor-arg name="typeKey">
<null />
</constructor-arg>
</bean>
<bean id="mongoMappingContext"
class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<bean id="mongoConverter"
class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mongoMappingContext" />
<property name="typeMapper" ref="mongoTypeMapper"></property>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mongoConverter" ref="mongoConverter" />
<property name="writeResultChecking" value="EXCEPTION" />
</bean>
</beans>
/---------------------------------------------------------------------------/
#Autowired
private MongoTemplate mongoTemplate ;
#Override
public String methodTesting(classname object) { //classname change to your class name
String response="failer";
try {
if (!mongoTemplate.collectionExists(classname.class)) {
mongoTemplate.createCollection(classname.class);
}
mongoTemplate.save(object);
`response="success";`
} catch (Exception e) {
System.out.println("inside catch");
e.printStackTrace(); // TODO: handle exception
}
return response;
}

Resources