How do I use a Citrus mail endpoint in an Arquillian test on JEE server - jboss-arquillian

I have a Java webapp where a REST call triggers a mail sent through a javax.mail.Session. The application is deployed as a .war archive that I want to test inside a JBoss EAP 7.2 server.
I am using Arquillian 1.5.0.Final and Citrus Framework version 2.8.0. My build system is Gradle 5.x and everything is using a Java 8 runtime.
I would like to create a Citrus mail endpoint and use Arquillian to provide this inside the JEE container. My experience with these frameworks is limited to a few days, so I'm starting with a sample application to gain more knowledge:
I have the following working against a simple web endpoint (The HelloServlet from https://guides.gradle.org/building-java-web-applications/):
#RunWith(Arquillian.class)
public class HelloServletTest {
#CitrusFramework
private Citrus citrusFramework;
#ArquillianResource
private URL baseUri;
private String serviceUri;
#Deployment(testable = false)
public static WebArchive createDeployment() {
final WebArchive war = ShrinkWrap.create(WebArchive.class)
.addClass(HelloServlet.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
// [...]
return war;
}
#Before
public void setUp() throws Exception {
serviceUri = new URL(baseUri, "hello").toExternalForm();
}
#Test
#CitrusTest
public void smokeTest(#CitrusResource TestDesigner designer) throws InterruptedException {
System.err.println("ServiceURI: " + serviceUri);
designer.send(serviceUri)
.message(new HttpMessage("?name=Jacob")
.method(HttpMethod.POST));
designer.receive(serviceUri).message(new HttpMessage("").status(HttpStatus.OK));
citrusFramework.run(designer.getTestCase());
}
}
I use #Deployment(testable=false) as this example runs a client-side test. However, my end goal is to use Citrus inside the container so my understanding is that I need to have #Deployment(testable=true). But when I run the test with testable=true a NPE is thrown:
java.lang.NullPointerException
at com.consol.citrus.annotations.CitrusAnnotations.injectAll(CitrusAnnotations.java:61)
at com.consol.citrus.arquillian.enricher.CitrusTestEnricher.enrich(CitrusTestEnricher.java:57)
at org.jboss.arquillian.junit.RulesEnricher.enrichInstances(RulesEnricher.java:85)
at org.jboss.arquillian.junit.RulesEnricher.enrichStatement(RulesEnricher.java:77)
[...]
at org.jboss.arquillian.core.impl.EventContextImpl.invokeObservers(EventContextImpl.java:103)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:90)
at org.jboss.arquillian.container.test.impl.client.ContainerEventController.createContext(ContainerEventController.java:128)
at org.jboss.arquillian.container.test.impl.client.ContainerEventController.createBeforeContext(ContainerEventController.java:114)
[...]
at org.jboss.arquillian.test.impl.EventTestRunnerAdaptor.fireCustomLifecycle(EventTestRunnerAdaptor.java:159)
at org.jboss.arquillian.junit.Arquillian$7.evaluate(Arquillian.java:273)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
[...]
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
[...]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.lang.Thread.run(Thread.java:748)
My arquillian.xml is
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 3.0"/>
<engine>
<property name="deploymentExportPath">build/deployments</property>
</engine>
<container qualifier="wildfly-managed" default="true">
</container>
<extension qualifier="citrus">
<property name="autoPackage">false</property>
<property name="citrusVersion">2.8.0</property>
</extension>
</arquillian>
My citrus-context.xml is
<?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:citrus-mail="http://www.citrusframework.org/schema/mail/config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.citrusframework.org/schema/mail/config http://www.citrusframework.org/schema/mail/config/citrus-mail-config.xsd">
<!-- Mail server mock -->
<citrus-mail:server id="mailServer"
auto-start="true"
port="2222"/>
</beans>
My questions are:
Does my approach make sense? Is it feasible to use Citrus and Arquillian in this way?
Is the NPE exception to be expected or am I missing some dependency or configuration?

Related

How to setup jms in Red Hat middleware to RabbitMQ

I run Red Hat middleware with CodeReady Studio 12.16.0.GA on standalone Spring-boot environment as local Camel context. I have local RabbitMQ running in Docker.
I have failed to setup any scenario using tutorials on web in/out JMS using Camel.
All tutorials don't use camel-context.xml configuration only pure java spring.
Please help me to configure camel-context.xml and all resource to use RabbitMQ or just any JMS.
Thanks in advance.
Here is simple camel-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring https://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route id="simple-route">
<from id="_to1" uri="jms:myQeue?connectionFactory=#myConnectionFactory&jmsMessageType=Text"/>
<log id="route-log" message=">>> ${body}"/>
</route>
</camelContext>
</beans>
and simple spring application to run it
package org.mycompany;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
#SpringBootApplication
#ImportResource({"classpath:spring/camel-context.xml"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But it went to exception
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: jms://myQeue?connectionFactory=%23myConnectionFactory&jmsMessageType=Text due to: No bean could be found in the registry for: myConnectionFactory of type: javax.jms.ConnectionFactory
I have added registration of ConnectionFactory
ConnectionFactory myCF = new ConnectionFactory();
myCF.setUsername("guest");
myCF.setPassword("guest");
myCF.setVirtualHost("/");
myCF.setHost("localhost");
myCF.setPort(5672);
SimpleRegistry reg = new SimpleRegistry();
reg.put("myConnectionFactory", myCF);
CamelContext camContext = new DefaultCamelContext(reg);
but new exception arose I think because of using com.rabbitmq.client.ConnectionFactory
Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route simple-route: Route(simple-route)[[From[jms:queue:myQeue?connectionFactory... because of connectionFactory must be specified
How to define javax.jms.ConnectionFactory to registry?

java.lang.ClassNotFoundException: org.eclipse.equinox.launcher.WebStartMain

I try to launch my RCP-project with jnlp. So i implemented a small e4-RCP project. Starting with the product doesn't cause any problem. The application supposedly works just fine. I installed a tomcat server running at localhost:8080, this also starts very well. Than i wrote a jnlp file for the app. exported and signed the jar. When i try to start the app. as http://localhost:8080/webstart.jnlp i get the exception:
java.lang.ClassNotFoundException: org.eclipse.equinox.launcher.WebStartMain
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at com.sun.jnlp.JNLPClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at com.sun.jnlp.JNLPClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at de.checkpoint.webstart.WebstartLauncher.main(WebstartLauncher.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.doLaunchApp(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Having said all all of that, here is my main:
package de.checkpoint.webstart;
import org.eclipse.equinox.launcher.WebStartMain;
public class WebstartLauncher {
public static void main(String[] args) {
WebStartMain.main(args);
}
}
Here is my jnlp file:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://localhost:8080/" href="webstart.jnlp">
<information>
<title>Jnlp Webstart Test</title>
<vendor>Boris Nguema B.</vendor>
<homepage href="http://localhost:8080/" />
<description>Testing Webstart</description>
</information>
<security>
<all-permissions/>
</security>
<!-- <property name="eclipse.product" value="de.checkpoint.product"/> -->
<!-- <property name="osgi.frameworkParentClassloader" value="current"/> -->
<!-- <property name="jnlp.osgi.parentClassloader" value="current"/> -->
<resources>
<j2se version="1.8+" />
<jar href="de.checkpoint.start_1.0.0.201711041646.jar" />
</resources>
<application-desc main-class="de.checkpoint.webstart.WebstartLauncher" />
</jnlp>
Can anyone tells me, what am I missing?
I am not sure if you already found out the problem,but equinox launcher do not have those lines in the manifest:
Permissions: all-permissions
Codebase: *
Trusted-Only: true
you need to add them and sign.

Jax-WS Axis2 Proxy over SSL error using ProxySelector

In my project I have the following project structure:
I have a module that is producing a war file and can be deployed inside a Tomcat application server. This module has dependencies on Axis2 libraries:
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-http</artifactId>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-webapp</artifactId>
<type>war</type>
</dependency>
And this class contains an axis2.xml file in the conf folder under WEB-INF.
Now this module has a dependency on a unit module, that has the package type of a jar.
Now in my web-module, in the code for my stub I have following code:
GazelleObjectValidator.getInstance().validateObject();
The XcpdValidationService is a class in the jar module (dependency) and this method calls an external web service over SSL and using a proxy.
This web service client is generated by JAX WS RI
BUT this class doesn't use the axis2.xml configuration from the parent module and uses it's own axis configuration, being the default one, where my proxy is not configured...
#WebEndpoint(name = "GazelleObjectValidatorPort")
public GazelleObjectValidator getGazelleObjectValidatorPort() {
return super.getPort(new QName("http://ws.validator.sch.gazelle.ihe.net/", "GazelleObjectValidatorPort"), GazelleObjectValidator.class);
}
The method itself looks like this:
#WebMethod
#WebResult(name = "validationResult", targetNamespace = "")
#RequestWrapper(localName = "validateObject", targetNamespace = "http://ws.validator.sch.gazelle.ihe.net/", className = "net.ihe.gazelle.schematron.ValidateObject")
#ResponseWrapper(localName = "validateObjectResponse", targetNamespace = "http://ws.validator.sch.gazelle.ihe.net/", className = "net.ihe.gazelle.schematron.ValidateObjectResponse")
public String validateObject(
#WebParam(name = "base64ObjectToValidate", targetNamespace = "")
String base64ObjectToValidate,
#WebParam(name = "xmlReferencedStandard", targetNamespace = "")
String xmlReferencedStandard,
#WebParam(name = "xmlMetadata", targetNamespace = "")
String xmlMetadata)
throws SOAPException_Exception
;
My GazelleObjectValidatorService is generated by following plugin:
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-aar-maven-plugin</artifactId>
<version>${axis2.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>package-aar</id>
<phase>prepare-package</phase>
<goals>
<goal>aar</goal>
</goals>
</execution>
</executions>
<configuration>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/main/resources/wsdl</directory>
<outputDirectory>META-INF</outputDirectory>
<includes>
<include>**/*.xsd</include>
</includes>
</fileSet>
</fileSets>
<servicesXmlFile>${project.build.outputDirectory}/axis2/services.xml</servicesXmlFile>
<wsdlFile>${project.build.outputDirectory}/wsdl/ClientConnectorService.wsdl</wsdlFile>
</configuration>
</plugin>
I tried to override the transportSender in my axis2.xml configuration with my own defined MyCommonsHttpTransportSender:
<transportSender name="http"
class="eu.epsos.pt.cc.MyCommonsHTTPTransportSender">
<parameter name="PROTOCOL">HTTP/1.1</parameter>
<parameter name="Transfer-Encoding">chunked</parameter>
and
<transportSender name="https"
class="eu.epsos.pt.cc.MyCommonsHTTPTransportSender">
<parameter name="PROTOCOL">HTTP/1.1</parameter>
<parameter name="Transfer-Encoding">chunked</parameter>
</transportSender>
that knows about the proxy.
but unfortunately since the web service client is inside the jar that is a dependency of the war, it doesn't seem to use my axis2.xml configuration, but uses it's own axis configuration, which doesn't know about the proxy.
This causes the following error where you see clearly that it uses the default CommonsHTTPTransportSender and therefore throwing the error:
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:140)
at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:130)
at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1361)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.axis2.transport.http.AbstractHTTPSender.executeMethod(AbstractHTTPSender.java:621)
at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:193)
at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:75)
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.writeMessageWithCommons(CommonsHTTPTransportSender.java:404)
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.invoke(CommonsHTTPTransportSender.java:231)
at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:443)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:406)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at org.apache.axis2.jaxws.core.controller.impl.AxisInvocationController.execute(AxisInvocationController.java:578)
at org.apache.axis2.jaxws.core.controller.impl.AxisInvocationController.doInvoke(AxisInvocationController.java:127)
at org.apache.axis2.jaxws.core.controller.impl.InvocationControllerImpl.invoke(InvocationControllerImpl.java:93)
at org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler.invokeSEIMethod(JAXWSProxyHandler.java:373)
... 40 common frames omitted
Is there a way to let the WS client in the child jar make use of the same axis2 configuration of the parent module (that is a deployable war and has the axis2 dependencies?)
UPDATE:
My WAR file has an axis2 configuration, from the source code of this war, a service generated with wsimport is called which is in a JAR that is a dependency of the parent WAR. This service calls an external WebService and this happens over Axis (although doesn't use the axis2.xml configuration file, since this one is in the WEB-INF folder of the JAR.
Wouldn't there be any possibility to make the external WebService call in the JAR without Axis and use just JAXWS? This would solve my problems...
Axis2 provides a convenient method to configure the HTTP Transport. So, following from your sample code:
HttpTransportProperties.ProxyProperties proxyProperties = new HttpTransportProperties.new ProxyProperties();
proxyProperties.setProxyHostName("hostName");
proxyProperties.setProxyPort("hostPort");
proxyProperties.setUsername("User");
proxyProperties.setPassword("pw");
//set the properties
objectValidatorService.getServiceClient().getOptions().setProperty(HttpConstants.PROXY, proxyProperties);
The above wouldn't work for you because you're using the stock JAX-WS implementation, not the Axis2-specific client.
Based on your stacktrace, it appears you're connecting to a TLS-secured endpoint. There's a solution for that
I've done a lot of research, and there's no access to the underlying HTTPUrlConnection using stock JAX-WS. What we do have, is a way to set a custom SSLContextFactory. So we start by creating a custom factory, that will connect to the proxy first:
public class CustomSocketFactory extends SSLProtocolSocketFactory {
private static final CustomSocketFactory factory = new CustomSocketFactory();
static CustomSocketFactory getSocketFactory(){
return factory;
}
public CustomSocketFactory() {
super();
}
#Override
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) {
Socket socket = null;
try {
int proxyPort = 1000;
InetSocketAddress proxyAddr = new InetSocketAddress("proxyAddr", proxyPort);
Socket proxyConn = new Socket(new Proxy(Proxy.Type.SOCKS, proxyAddr));
proxyConn.connect(new InetSocketAddress("endHost", 443));
socket = (SSLSocket) super.createSocket(proxyConn, "proxyEndpoint", proxyPort, true);
} catch (IOException ex) {
Logger.getLogger(CustomSocketFactory.class.getName()).log(Level.SEVERE, null, ex);
}
return socket;
}
}
we'll now register this custom socket factory with the Apache HTTPClient runtime (Axis does not use the stock java HTTPUrlConnection, as is evidenced by your stacktrace):
Protocol.registerProtocol("https",new Protocol("https", new CustomSocketFactory(), 443));
This works only for TLS connections. (although, a custom socket factory is applicable to non-https endpoints also). You also need to set the timeout to 0 so we can guarantee that your overriden createSocket gets invoked

Arquillian - How to debug managed Wildfly container

I am using Arquillian to write black box tests for my RESTful application. I am actually capable of debug the test classes, but unable to debug my application classes. I would like to know exactly how to do that.
My arquillian.xml:
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<container qualifier="jbossas-managed" default="true">
<configuration>
<property name="jbossHome">D:\desenv\arquivos\servidores\wildfly-9.0.1.Final-test</property>
<property name="allowConnectingToRunningServer">true</property>
<property name="javaVmArguments">-Dorg.apache.deltaspike.ProjectStage=IntegrationTest</property>
</configuration>
</container>
One of my test classes:
#RunAsClient
#RunWith(Arquillian.class)
public class AuthenticationBlackBoxTest extends AbstractBlackBoxTest {
#Test
public void testInvalidCredentials(#ArquillianResource URL baseURI) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(baseURI.toString()).path("api/v1/auth");
Response response = target.request(MediaType.APPLICATION_JSON)
.post(Entity.entity(new Credentials("invalid", "invalid"), MediaType.APPLICATION_JSON));
Assert.assertEquals(401, response.getStatus());
response.close();
client.close();
}
#Test
public void testValidCredentials(#ArquillianResource URL baseURI) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(baseURI.toString()).path("api/v1/auth");
Entity<Credentials> credentialsEntity = Entity.entity(new Credentials("adm#adm.com", "123"), MediaType.APPLICATION_JSON);
Response response = target.request(MediaType.APPLICATION_JSON)
.post(credentialsEntity);
Assert.assertEquals(200, response.getStatus());
response.close();
client.close();
}
}
Inside arquillian.xml for javaVmArguments element add -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y.
Then in your favourite IDE you have to define a new Remote Debug configuration where you specify the host(localhost), port(8787). Place your break point, then run your test and finally start the remote debug. Official doc here.

AspectJ AOP and Spring together

I want to use AspectJ AOP and Spring (for DI) together but I get following exception:
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class
I use IntelliJ IDEA 12 Ultimate IDE.
Here are the example steps to reproduce the error.
1: Info interface:
package org.example.bugs.bug;
public interface Info {
public void info();
}
2: Interface implementation:
package org.example.bugs.bug;
public class Informer implements Info {
#Override
public void info() {
System.out.println("Some info from Informer!");
}
}
3: Aspect:
package org.example.bugs.bug;
public aspect InfoAspect {
public InfoAspect() {}
pointcut info() : execution(* org.example.bugs.bug.Informer.info(..));
after() returning() : info() {
System.out.println("Information confirmed by InfoAspect!");
}
}
4: spring-config.xml file:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
<bean id="informer"
class="org.example.bugs.bug.Informer"/>
<bean class="org.example.bugs.bug.InfoAspect"
factory-method="aspectOf"/>
</beans>
5: I run everything in following Main class:
package org.example.bugs.bug;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("org/example/bugs/bug/spring-config.xml");
Info i = (Info) context.getBean("informer");
i.info();
}
}
...and I get error:
2013-03-24 15:46:10 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#f81843: startup date [Sun Mar 24 15:46:10 CET 2013]; root of context hierarchy
2013-03-24 15:46:10 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [org/example/bugs/bug/spring-config.xml]
2013-03-24 15:46:10 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13ad085: defining beans [org.springframework.aop.config.internalAutoProxyCreator,informer,org.example.bugs.bug.InfoAspect#0]; root of factory hierarchy
2013-03-24 15:46:10 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13ad085: defining beans [org.springframework.aop.config.internalAutoProxyCreator,informer,org.example.bugs.bug.InfoAspect#0]; root of factory hierarchy
Exception in thread "main" org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.example.bugs.bug.InfoAspect] for bean with name 'org.example.bugs.bug.InfoAspect#0' defined in class path resource [org/example/bugs/bug/spring-config.xml]; nested exception is java.lang.ClassNotFoundException: org.example.bugs.bug.InfoAspect
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1266)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:629)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:578)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1335)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:901)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at org.example.bugs.bug.Main.main(Main.java:8)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.ClassNotFoundException: org.example.bugs.bug.InfoAspect
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:260)
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:416)
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1287)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1258)
... 15 more
What I do wrong?
Because you are trying to use a pointcut supported by Spring AOP I advice you to use Spring AOP for this. Using spring with full feature set AspectJ is a little bit complicated because it requires the advice weaving. Moreover the <aop:aspectj-autoproxy /> is for #AspectJ-style spring AOP, but is still a Spring proxying the targets, not AspectJ.
So I would convert the example aspect as per below:
#Aspect
public class InfoAspect {
public InfoAspect() {
}
#Pointcut("execution(* prospring3.aop.aspectj.Informer.info(..))")
void infoPointcut() {
}
#AfterReturning("infoPointcut()")
public void afterReturning(JoinPoint joinPoint) {
System.out.println("Information confirmed by InfoAspect!");
System.out.println("joinPoint.getSignature().getName() = " + joinPoint.getSignature().getName());
}
}
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass = true) // use the CGLib instead of Java Proxy
public class AspectJConfig {
#Bean
public Info info() {
return new Informer();
}
/**
* Aspect must be a config as a bean
* #return the aspect
*/
#Bean
public InfoAspect infoAspect() {
return new InfoAspect();
}
}
public class InformerTest {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AspectJConfig.class);
final Info bean = ctx.getBean(Info.class);
bean.info();
}
}
Note: include the following dependencies in pom.xml
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
Regads
You're missing your InfoAspect class..
Did you not see ClassNotFound for org.example.bugs.bug.InfoAspect in the stack trace? Perhaps it's not being compiled by Aspect J.
Maybe you need another tutorial:
http://www.tutorialspoint.com/spring/aspectj_based_aop_appoach.htm
I would make sure that you've got Spring 3 and use the latest idiom.