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
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.
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.
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>
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
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;
}