#Around Advice Not working with Controller. #Before,#After etc working without errors - spring-aop

I am trying to use the Around method around my rest controller using a logger class. I get the output "Before calling Controller","After calling controller" etc, but I don't get any return result in my postman.
The code works fine with #Before method and #After.
The ReST Controller looks like this.
#RestController("/")
public class DummyController {
#RequestMapping(value="hello",method=RequestMethod.GET)
public String dummyMethod() {
System.out.println("In Controller...");
return "Hello There";
}
}
This is the Aspect class.
#Aspect
#Component
public class Logger {
#Around("within(DummyController)")//Around Not working....
public void printMessage(ProceedingJoinPoint p) throws Throwable
{
System.out.println("Before Calling Method...");
p.proceed();
System.out.println("After calling method...");
}
The bean configuration is as below:
<mvc:annotation-driven />
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.aop.test"> </context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
My output is:
Before Calling Method...
In Controller...
After calling method...
But the webservice output is blank in postman instead of "Hello There". The status is "200 OK"
The code works as expected with other Advices like #Before,#After...
Any pointers on where the code went wrong?
Thanks in Advance..

change your Aspect to below and it should work.
#Aspect
#Component
public class Logger {
#Around("within(DummyController)")//Around Not working....
public Object printMessage(ProceedingJoinPoint p) throws Throwable
{
System.out.println("Before Calling Method...");
Object result = p.proceed();
System.out.println("After calling method...");
return result;
}
Notice that I made the advice return the object returned by ProceedingJoinPoint

Related

Simple Camel test fails with no messages recieved

Am using Spring Boot and I have just added camel to it.
I have a simple camel route setup :
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
#Component
public class MyRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("file://in").to("file://out");
}
}
When I try to create simple test for this route with :
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class MyRouteTest extends CamelTestSupport {
#Autowired
private CamelContext camelContext;
#Produce(uri = "file://in")
private ProducerTemplate producerTemplate;
#EndpointInject(uri = "mock:file://out")
private MockEndpoint mockEndpoint;
#Test
public void routeTest() throws Exception {
mockEndpoint.expectedMessageCount(1);
producerTemplate.sendBody("Test");
mockEndpoint.assertIsSatisfied();
}
}
It fails with
mock://file://out Received message count. Expected: <1> but was: <0>
Not sure what could be a problem here. I have producer template that has uri as my route from point and am mocking to endpoint with EndpointInject and the the mock uri?
Fixed but not 100%
If I change route from real one
from("file://in").to("file://out");
to
from("file://in").to("mock:out");
And in my test override
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new MyRoute();
}
to create specific route
and strangest of all ! Had to remove :
#SpringBootTest
and after that
private CamelContext camelContext;
And then it started working !
But unfortunately not what I need, still there are things that need to be fixed, I would like to use my real prod route !
from("file://in").to("file://out");
And if possible not use advise on route , but just mock it , tried with
mock:file://out in test, but it didnt work :(
and also , it does not work with #SpringBootTest ??? very strange ?!
You need to add
#Override
public String isMockEndpoints() {
return "*";
}
This should mock all the enpoints and then you can use mock:file:out for example
If I am not misstaken you are mocking your output endpoint yet your endpoint endpoint is a file endpoint. When you send a message you need to drop a message to whereever the file endpoint is polling. Otherwise you need to mock that as well.

Camel blueprint testing and cucumber

Is it possible to combine cucumber with CamelBlueprintTestSupport? I have my runner class:
#RunWith(Cucumber.class)
#CucumberOptions(monochrome=true,
format={ "pretty", "html:target/cucumber"},
features = "C:/Users/Developer/workspace_camel/SRV002_PatronInformation/src/test/resources/cucumber/asynchronousErrorHandling.feature")
public class RunFeature_SRV002_PatronInformationTest {
}
and my blueprint test class with the scenarios:
public class SRV002_PatronInformationScenarioTest extends CamelBlueprintTestSupport {
#Override
protected String getBlueprintDescriptor() {
return "/OSGI-INF/blueprint/blueprint.xml";
}
#Given("^client communicates asynchronous via socket$")
public void client_communicates_asynchronous_via_socket() throws Throwable {
System.out.println("test");
}
#When("^client posts message$")
public void an_error_occurs_inside_the_integration() throws Throwable {
String endpoint = "netty4:tcp://localhost:5000?sync=false&textline=true";
template.sendBody(endpoint, "test");
}
#Then("^the integration should not return response to the client$")
public void the_integration_should_not_return_the_error_to_the_client() throws Throwable {
System.out.println("test");
}
}
The problem now is that, when I run this I run into nullpointerexception at template.sendbody because the context, bundle and routes haven't started. For some reason it seems adding #RunWith(Cucumber) prevents the camel routes from starting.
Anyone knows how this can be solved? Thanks
Souciance
Ok so I managed to solve this.
For reference look here:
http://camel.465427.n5.nabble.com/How-to-test-routes-when-using-another-TestRunner-td5772687.html
Thanks to Gregor Lenz for the help.
Essentially the key here is that in your Camel BlueprintTestSupport class, inside the test method, that starts the given scenario you need to add this.setUp(). See the code below:
In Cucumber
SRVXXX_FileTransferCamelRunner filetransfer = new SRVXXX_FileTransferCamelRunner();
#Given("^an input file$")
public void an_input_file() throws Throwable {
endpoint.append("file:C:/Camel/input?fileName=input.txt");
}
#When("^client puts the file in the input directory$")
public void client_puts_the_file_in_the_input_directory() throws Throwable {
filetransfer.testPutFile(fileData.toString(), endpoint.toString());
}
#Then("^the integration should move the file to the output directory$")
public void the_integration_should_move_the_file_to_the_output_directory() throws Throwable {
String outputPath = "C:/Camel/output/input.txt";
filetransfer.testFileHasMoved(outputPath);
}
In Camel
#Test
public void testPutFile(String body, String endpoint) throws Exception {
this.setUp();
template.sendBody(endpoint,body);
Thread.sleep(2000);
assertFileNotExists(endpoint);
}

camel return value from external Web Service

I need to invoke an external Web service running on WildFly from camel.
I managed to invoke it using the following route:
public class CamelRoute extends RouteBuilder {
final String cxfUri =
"cxf:http://localhost:8080/DemoWS/HelloWorld?" +
"serviceClass=" + HelloWorld.class.getName();
#Override
public void configure() throws Exception {
from("direct:start")
.id("wsClient")
.log("${body}")
.to(cxfUri + "&defaultOperationName=greet");
}
}
My question is how to get the return value from the Web service invocation ? The method used returns a String :
#WebService
public class HelloWorld implements Hello{
#Override
public String greet(String s) {
// TODO Auto-generated method stub
return "Hello "+s;
}
}
If the service in the Wild Fly returns the value then to see the values you can do the below
public class CamelRoute extends RouteBuilder {
final String cxfUri =
"cxf:http://localhost:8080/DemoWS/HelloWorld?" +
"serviceClass=" + HelloWorld.class.getName();
#Override
public void configure() throws Exception {
from("direct:start")
.id("wsClient")
.log("${body}")
.to(cxfUri + "&defaultOperationName=greet").log("${body}");
//beyond this to endpoint you can as many number of componenets to manipulate the response data.
}
}
The second log will log the response from the web service that you are returning. If you need to manipulate or do some routing and transformation with the response then you should look at the type of the response and accordingly you should use appropriate transformer.
Hope this helps.

Unable to mock GAE userservice

I am trying to mock the gae user service for writing unit tests and couldn't get the following code to work.
My test class is as below.
public class AuthenticationTest {
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalUserServiceTestConfig())
.setEnvIsAdmin(true).setEnvIsLoggedIn(true)
.setEnvEmail("test#example.com");
#Before
public void setUp() {
helper.setUp();
}
#After
public void tearDown() {
helper.tearDown();
}
#Test
public void testIsAdmin() {
UserService userService = UserServiceFactory.getUserService();
assertTrue(userService.isUserAdmin());
String email = userService.getCurrentUser().getEmail();
assertEquals(email, "test#example.com");
}
}
I find that userService.getCurrentUser() always returns null.
Most of the code is taken from the example in developers.google.com. The only thing I added is call to .setEnvEmail("test#example.com")
Any help would be appreciated.
Thanks,
Sathya
in order to mock email, the auth domain also needs to be mocked, just add
.setEnvAuthDomain("example.com");
to your helper initialisation or in #Before method post initialise and it will work fine.
hope it helps

Intercepting annotated methods using Spring #Configuration and MethodInterceptor

I need to intercept annotated methods using spring-aop.
I already have the interceptor, it implements MethodInterceptor from AOP Alliance.
Here is the code:
#Configuration
public class MyConfiguration {
// ...
#Bean
public MyInterceptor myInterceptor() {
return new MyInterceptor();
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
// ...
}
public class MyInterceptor implements MethodInterceptor {
// ...
#Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
//does some stuff
}
}
From what I've been reading it used to be that I could use a #SpringAdvice annotation to specify when the interceptor should intercept something, but that no longer exists.
Can anyone help me?
Thanks a lot!
Lucas
MethodInterceptor can be invoked by registering a Advisor bean as shown below.
#Configurable
#ComponentScan("com.package.to.scan")
public class AopAllianceApplicationContext {
#Bean
public Advisor advisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("#annotation(com.package.annotation.MyAnnotation)");
return new DefaultPointcutAdvisor(pointcut, new MyInterceptor());
}
}
In case anyone is interested in this... apparently this can't be done.
In order to use Java solely (and no XML class) you need to use AspectJ and Spring with #aspect annotations.
This is how the code ended up:
#Aspect
public class MyInterceptor {
#Pointcut(value = "execution(* *(..))")
public void anyMethod() {
// Pointcut for intercepting ANY method.
}
#Around("anyMethod() && #annotation(myAnnotation)")
public Object invoke(final ProceedingJoinPoint pjp, final MyAnnotation myAnnotation) throws Throwable {
//does some stuff
...
}
}
If anyone else finds out something different please feel free to post it!
Regards,
Lucas

Resources