ClassNotFoundException when using anonymous class in Pax Exam test method - osgi

I'm getting a ClassNotFoundException when using an anonymous class in a Pax Exam test method.
My test class:
package com.bssys.ebpp.paxexam;
import static org.ops4j.pax.exam.CoreOptions.maven;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.*;
import org.apache.camel.Processor;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.component.jdbc.JdbcComponent;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.impl.SimpleRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.ProbeBuilder;
import org.ops4j.pax.exam.TestProbeBuilder;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.karaf.options.LogLevelOption;
import org.ops4j.pax.exam.util.Filter;
import org.osgi.framework.Constants;
import javax.inject.Inject;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import java.io.File;
/**
* #author zhupv
*/
#RunWith(PaxExam.class)
public class TransactionsTest {
#Inject
#Filter(timeout = 30000)
Transactions transactions;
#Inject
DataSource dataSource;
#Configuration
public Option[] config() {
return new Option[]{
karafDistributionConfiguration()
.frameworkUrl(
maven()
.groupId("org.apache.servicemix")
.artifactId("apache-servicemix")
.type("zip")
.version("6.0.0.M2")
)
.karafVersion("3.0.3")
.name("Apache ServiceMix")
.unpackDirectory(new File("target/pax"))
.useDeployFolder(false),
keepRuntimeFolder(),
debugConfiguration("5005", true),
logLevel(LogLevelOption.LogLevel.DEBUG),
features(
maven().groupId("org.apache.karaf.features").artifactId("enterprise").version("3.0.3").type("xml").classifier("features"),
"transaction"
),
features(
maven().groupId("org.apache.camel.karaf").artifactId("apache-camel").version("2.15.2").type("xml").classifier("features"),
"camel", "camel-blueprint", "camel-core", "camel-spring", "camel-jdbc"
),
mavenBundle()
.groupId("com.h2database")
.artifactId("h2")
.version("1.4.187")
.start(),
mavenBundle()
.groupId("com.bssys.ebpp")
.artifactId("sandbox-services")
.version("1.0.0")
.start()
};
}
#ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
System.out.println("TestProbeBuilder gets called");
probe.setHeader(Constants.DYNAMICIMPORT_PACKAGE, "*");
return probe;
}
#Test
public void test() throws Exception{
try{
SimpleRegistry sr = new SimpleRegistry();
sr.put("ds", dataSource);
CamelContext camelContext = new DefaultCamelContext(sr);
camelContext.addComponent("jdbc", new JdbcComponent());
ProducerTemplate producerTemplate = camelContext.createProducerTemplate();
producerTemplate.sendBody(
"jdbc://ds",
"create table if not exists test_table(col1 varchar(255))"
);
Endpoint endpoint = camelContext.getEndpoint("jdbc://ds");
Exchange exchange = endpoint.createExchange();
exchange.getIn().setBody("select count(*) from test_table");
Exchange out = producerTemplate.send(endpoint, exchange);
out = producerTemplate.send(
"jdbc://ds",
new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody(
"select count(*) from test_table"
);
}
}
);
transactions.doWork();
} catch (Exception ex){
ex.printStackTrace();
}
}
}
The stacktrace:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.7.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)[:1.7.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606)[:1.7.0_25]
at org.ops4j.pax.exam.rbc.internal.RemoteBundleContextImpl.remoteCall(RemoteBundleContextImpl.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.7.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)[:1.7.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606)[:1.7.0_25]
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)[:1.7.0_25]
at sun.rmi.transport.Transport$1.run(Transport.java:177)[:1.7.0_25]
at sun.rmi.transport.Transport$1.run(Transport.java:174)[:1.7.0_25]
at java.security.AccessController.doPrivileged(Native Method)[:1.7.0_25]
at sun.rmi.transport.Transport.serviceCall(Transport.java:173)[:1.7.0_25]
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)[:1.7.0_25]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)[:1.7.0_25]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)[:1.7.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)[:1.7.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)[:1.7.0_25]
at java.lang.Thread.run(Thread.java:724)[:1.7.0_25]
Caused by: org.ops4j.pax.exam.TestContainerException: [test(com.bssys.ebpp.paxexam.TransactionsTest): com/bssys/ebpp/paxexam/TransactionsTest$1]
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.createTestContainerException(JUnitProbeInvoker.java:138)
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.invokeViaJUnit(JUnitProbeInvoker.java:127)
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.findAndInvoke(JUnitProbeInvoker.java:97)
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.call(JUnitProbeInvoker.java:73)
... 20 more
Caused by: java.lang.NoClassDefFoundError: com/bssys/ebpp/paxexam/TransactionsTest$1
at com.bssys.ebpp.paxexam.TransactionsTest.test(TransactionsTest.java:111)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.7.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)[:1.7.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606)[:1.7.0_25]
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:68)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:37)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.invokeViaJUnit(JUnitProbeInvoker.java:124)
... 22 more
Caused by: java.lang.ClassNotFoundException: com.bssys.ebpp.paxexam.TransactionsTest$1 not found by sandbox-services [159]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1532)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)[:1.7.0_25]
at org.apache.felix.framework.BundleWiringImpl.getClassByDelegation(BundleWiringImpl.java:1374)
at org.apache.felix.framework.BundleWiringImpl.searchImports(BundleWiringImpl.java:1553)
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1484)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)[:1.7.0_25]
... 44 more
The exception gets raised when the probe executes the following code:
out = producerTemplate.send(
"jdbc://ds",
new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody(
"select count(*) from test_table"
);
}
}
);
Does somebody have an idea what's the reason behind this?
EDIT: I'm using Pax Exam 4.5.0

The root cause is the ClassNotFoundException in bundle sandbox-services, which tries to load the test class from your Exam probe bundle. This fails because by default, the probe does not export any packages. Adding an Export-Package header with the TestProbeBuilder should make this work:
#ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
System.out.println("TestProbeBuilder gets called");
probe.setHeader(Constants.DYNAMICIMPORT_PACKAGE, "*");
probe.setHeader(Constants.EXPORT_PACKAGE, "com.bssys.ebpp.paxexam");
return probe;
}

Related

Spring integration email pop3 inbound adapter not working/starting

With java spring integration written the below code to read the email from gmail.
As per logs seems the connection with gmail is formed, but on new email its not reading or not going into handle() method. Please help.
o.s.i.m.AbstractMailReceiver - attempting to receive mail from folder [INBOX]
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.mail.MailReceiver;
import org.springframework.integration.mail.dsl.Mail;
import org.springframework.integration.mail.support.DefaultMailHeaderMapper;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.messaging.Message;
import org.springframework.messaging.PollableChannel;
import javax.mail.internet.MimeMessage;
#Log4j2
#Configuration
#EnableIntegration
public class EmailReceiver {
#Autowired
private PollableChannel pop3Channel;
#Bean
public PollableChannel receivedChannel() {
return new QueueChannel();
}
#Bean
public IntegrationFlow pop3MailFlow() {
return IntegrationFlows
.from(Mail.pop3InboundAdapter("pop.gmail.com", 995, "userName", "password")
.javaMailProperties(p -> {
p.put("mail.debug", "true");
p.put("mail.pop3.socketFactory.fallback", "false");
p.put("mail.pop3.port", 995);
p.put("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
p.put("mail.pop3.socketFactory.port", 995);
})
.headerMapper(mailHeaderMapper()),
e -> e.poller(Pollers.fixedRate(5000).maxMessagesPerPoll(1)))
.handle((payload, header) -> logMail(payload))
.get();
}
public Message logMail(Object payload) {
Message message = (Message)payload;
log.info("*******Email[TEST]********* ", payload);
return message;
}
#Bean
public HeaderMapper<MimeMessage> mailHeaderMapper() {
return new DefaultMailHeaderMapper();
}
}
The problem is here:
.maxFetchSize(1)
By default the AbstractMailReceiver tries to fetch all the messages from the mail box. And looks like it takes a lot of time.
Another problem that with the .headerMapper(mailHeaderMapper() a Mail.pop3InboundAdapter does not produce a Message but rather byte[]. So, your .handle((payload, header) -> logMail(payload)) not only bad by the request-reply definition in the end of flow, but also fails with ClassCast like this, because you expect the type which is not produced for you:
Caused by: java.lang.ClassCastException: class [B cannot be cast to class org.springframework.messaging.Message ([B is in module java.base of loader 'bootstrap'; org.springframework.messaging.Message is in unnamed module of loader 'app')
at com.firm.demo.EmailReceiver.logMail(EmailReceiver.java:59)
at com.firm.demo.EmailReceiver.lambda$pop3MailFlow$2(EmailReceiver.java:53)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
Well, no: better to say you are missing the fact that this signature .handle((payload, header) -> logMail(payload)) deals with the payload not the whole message. So, your expectations in the logMail() are wrong. It has to be byte[]. And consider to have a one-way handler over there in the end of flow anyway.
UPDATE
The working code is like this:
#Log4j2
#Configuration
#EnableIntegration
public class EmailReceiver {
#Autowired
private PollableChannel pop3Channel;
private MailReceiver receiver;
#Bean
public PollableChannel receivedChannel() {
return new QueueChannel();
}
#Bean
public IntegrationFlow pop3MailFlow() {
return IntegrationFlows
.from(Mail.pop3InboundAdapter("pop.gmail.com", 995, "userName", "password")
.javaMailProperties(p -> {
p.put("mail.debug", "false");
p.put("mail.pop3.socketFactory.fallback", "false");
p.put("mail.pop3.port", 995);
p.put("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
p.put("mail.pop3.socketFactory.port", 995);
})
.maxFetchSize(1)
.headerMapper(mailHeaderMapper()),
e -> e.poller(Pollers.fixedRate(5000).maxMessagesPerPoll(1)))
.handle(this, "logMail")
.get();
}
public void logMail(String payload) {
log.info("*******Email[TEST]********* \n" + payload);
}
#Bean
public HeaderMapper<MimeMessage> mailHeaderMapper() {
return new DefaultMailHeaderMapper();
}
}

Spring Cloud Stream function with Spring Cloud Contract

I am trying to test the consumer of my event producer using StubTrigger.
Here is my contract:
import org.springframework.cloud.contract.spec.Contract
Contract.make {
label "sendUserMessage"
input {
triggeredBy("sendUserMessageTriggered()")
}
outputMessage {
sentTo"users-out-0"
body '''{ "email": "existing-user#email.com", "location": [10.0, 20.5], "area": 3.5 }'''
}
}
the yml from the producer:
spring:
profiles: "local"
cloud:
stream:
source: users
bindings:
users-out-0.destination: users
config:
enabled: false
discovery.enabled: false
discovery:
enabled: false
Here is the consumer bean definition:
package br.com.marco.cadeacerva.notification.infra.config;
import br.com.marco.cadeacerva.notification.domain.UsersEventConsumer;
import br.com.marco.cadeacerva.notification.endpoints.dto.UserDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.function.Consumer;
#Configuration
#Slf4j
#RequiredArgsConstructor
public class FunctionsConfig {
private final UsersEventConsumer usersEventConsumer;
#Bean
public Consumer<UserDTO> users() {
return (u) -> {
log.info("Received user on users function: {}", u.toString());
usersEventConsumer.consume(u);
};
}
}
Here is my consumer test:
package br.com.marco.cadeacerva.notification.infra.config;
import br.com.marco.cadeacerva.notification.domain.UsersEventConsumer;
import br.com.marco.cadeacerva.notification.endpoints.dto.UserDTO;
import br.com.marco.cadeacerva.testcommons.utils.annotation.IntegrationTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.cloud.contract.stubrunner.StubTrigger;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.test.context.junit4.SpringRunner;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
#RunWith(SpringRunner.class)
#IntegrationTest
#SpringBootTest
#AutoConfigureStubRunner(
stubsMode = StubRunnerProperties.StubsMode.LOCAL,
ids = "br.com.marco.cadeacerva:users:+:stubs:8090")
public class FunctionsConfigTest {
#Autowired
StubTrigger trigger;
#MockBean
UsersEventConsumer consumer;
#Test
public void shouldConsumeUsersEvents() {
trigger.trigger("sendUserMessage");
verify(consumer).consume(any(UserDTO.class));
}
}
And the consumer yml:
spring:
profiles: "integration-tests"
cloud:
stream:
bindings:
users-in-0:
destination: users
group: users
config:
enabled: false
discovery.enabled: false
discovery:
enabled: false
eureka:
client:
enabled: false
When I run the test it fails because of:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'users-out-0' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:814)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1282)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1114)
at org.springframework.cloud.contract.verifier.messaging.stream.StreamFromBinderMappingMessageSender.send(StreamFromBinderMappingMessageSender.java:57)
at org.springframework.cloud.contract.verifier.messaging.stream.StreamFromBinderMappingMessageSender.send(StreamFromBinderMappingMessageSender.java:51)
at org.springframework.cloud.contract.verifier.messaging.stream.StreamStubMessages.send(StreamStubMessages.java:44)
at org.springframework.cloud.contract.stubrunner.spring.LazyMessageVerifier.send(StubRunnerConfiguration.java:212)
at org.springframework.cloud.contract.stubrunner.StubRunnerExecutor.sendMessage(StubRunnerExecutor.java:260)
at org.springframework.cloud.contract.stubrunner.StubRunnerExecutor.triggerForDsls(StubRunnerExecutor.java:215)
at org.springframework.cloud.contract.stubrunner.StubRunnerExecutor.trigger(StubRunnerExecutor.java:200)
at org.springframework.cloud.contract.stubrunner.StubRunner.trigger(StubRunner.java:163)
at org.springframework.cloud.contract.stubrunner.BatchStubRunner.trigger(BatchStubRunner.java:136)
at br.com.marco.cadeacerva.notification.infra.config.FunctionsConfigTest.shouldConsumeUsersEvents(FunctionsConfigTest.java:35)
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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
I even tried to define the same source configuration from my producer, on the consumer, but got the same exception. Don't know what I'm supposed to do in this case...
Here you have an example of the new Stream API and Spring Cloud Contract on the consumer side: https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/3.0.x/consumer/src/test/java/com/example/BeerVerificationListenerTest.java Remember to ensure that you have the stream test dependency on the classpath
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<type>test-jar</type>
<scope>test</scope>
<classifier>test-binder</classifier>
</dependency>
As for your code, your sentTo should point to users not users-out-0.
Let me copy paste what's there in the code.
Consumer side listener
package com.example;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
/**
* #author Marcin Grzejszczak
*/
#Component("input")
class BeerVerificationListener implements Consumer<BeerVerificationListener.Verification> {
private static final Log log = LogFactory.getLog(BeerVerificationListener.class);
AtomicInteger eligibleCounter = new AtomicInteger();
AtomicInteger notEligibleCounter = new AtomicInteger();
#Override
public void accept(Verification verification) {
log.info("Received new verification");
//remove::start[]
//tag::listener[]
if (verification.eligible) {
this.eligibleCounter.incrementAndGet();
} else {
this.notEligibleCounter.incrementAndGet();
}
//end::listener[]
//remove::end[]
}
public static class Verification {
public boolean eligible;
}
}
Consumer side setup
spring:
application.name: beer-api-consumer
# remove::start[]
cloud.stream.bindings.input-in-0.destination: verifications
# remove::end[]
server.port: ${PORT:8081}
logging:
level:
org.springframework.cloud: debug
Producer side code
package com.example;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.stereotype.Service;
/**
* #author Marcin Grzejszczak
*/
#Service
public class AgeCheckingPersonCheckingService implements PersonCheckingService {
private final StreamBridge source;
public AgeCheckingPersonCheckingService(StreamBridge source) {
this.source = source;
}
#Override
public Boolean shouldGetBeer(PersonToCheck personToCheck) {
//remove::start[]
//tag::impl[]
boolean shouldGetBeer = personToCheck.age >= 20;
this.source.send("output-out-0", new Verification(shouldGetBeer));
return shouldGetBeer;
//end::impl[]
//remove::end[return]
}
public static class Verification {
boolean eligible;
public Verification(boolean eligible) {
this.eligible = eligible;
}
public Verification() {
}
public boolean isEligible() {
return this.eligible;
}
public void setEligible(boolean eligible) {
this.eligible = eligible;
}
}
}
Producer side setup
spring:
application.name: beer-api-producer
cloud.function.definition: output
cloud.stream.bindings.output-out-0:
# remove::start[]
destination: verifications
# remove::end[]
server.port: ${PORT:8080}
logging:
level:
org.springframework.cloud: debug
Contract definition
package contracts.beer.messaging
import com.example.ProducerUtils
import org.springframework.cloud.contract.spec.Contract
Contract.make {
description("""
Sends a positive verification message when person is eligible to get the beer
```
given:
client is old enough
when:
he applies for a beer
then:
we'll send a message with a positive verification
```
""")
// Label by means of which the output message can be triggered
label 'accepted_verification'
// input to the contract
input {
// the contract will be triggered by a method
triggeredBy('clientIsOldEnough()')
}
// output message of the contract
outputMessage {
// destination to which the output message will be sent
sentTo 'verifications'
// the body of the output message
body(
eligible: true
)
headers {
messagingContentType(applicationJson())
}
}
}

how to add header in JAXRSClientFactoryBean or JAXRSClientFactory

I am trying to use JAXRSClientFactoryBean or JAXRSClientFactory in the following way:
JAXRSClientFactoryBean example
Map<String, String> headerMap = new HashMap<String, String>();
headerMap.put("X-XSRF-TOKEN", "dummy_token");
headerMap.put("Cookie", "XSRF-TOKEN=dummy_token");
headerMap.put("Content-Type", "application/x-www-form-urlencoded");
headerMap.put("Accept", "application/json, text/plain, */*");
headerMap.put("Connection", "keep-alive");
headerMap.put("Host", "localhost.fr:8080");
headerMap.put("Referer", "http://localhost:8080/");
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
bean.setHeaders(headerMap);
bean.setResourceClass(SampleService.class);
bean.setAddress("http://localhost:8080/");
bean.setUsername("test");
bean.setPassword("test");
bean.setInheritHeaders(true);
SampleService test1 = bean.create(SampleService.class);
System.out.println(test1.getUser(1l));
JAXRSClientFactory example
SampleService sampleService = JAXRSClientFactory.create("http://localhost:8080/", SampleService.class, "test", "test", null);
System.out.println(sampleService.getUser(1l));
SampleService
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.springframework.http.ResponseEntity;
#Path("/api")
public interface SampleService {
#GET
#Path("/users/{id}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public ResponseEntity<XUser> getUser(#PathParam("id") Long id);
}
in both of the cases I am getting the below exception
Exception in thread "main" javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.apache.cxf.jaxrs.client.AbstractClient.convertToWebApplicationException(AbstractClient.java:505)
at org.apache.cxf.jaxrs.client.ClientProxyImpl.checkResponse(ClientProxyImpl.java:319)
at org.apache.cxf.jaxrs.client.ClientProxyImpl.handleResponse(ClientProxyImpl.java:827)
at org.apache.cxf.jaxrs.client.ClientProxyImpl.doChainedInvocation(ClientProxyImpl.java:789)
at org.apache.cxf.jaxrs.client.ClientProxyImpl.invoke(ClientProxyImpl.java:230)
at com.sun.proxy.$Proxy13.getXUser(Unknown Source)
at com.exadatum.xcatalyst.xstudio.publisher.AuthenticatorJAXRS.main(AuthenticatorJAXRS.java:55)
because I have used SecurityConfiguration class in spring for authentication like loginProcessingUrl("/api/authentication")
So anybody who came across this problem please help.
Any pointers/suggestion are welcome
Maybe I am thinking to obvious but it looks like the user is indeed not authorized :).
Could you make sure that your SecurityConfiguration class has access to your user information (username:test/password: test)? For test purposes you can setup global security definitions with inMemoryAuthentication().

Spring Integration Flow route based on file name

I have a requirement to unzip and file and process its contents. Inside the zip file, there could be two types of file individual or firm. That can be distinguished by file name. After processing of all files, it should call another program module, also archive the processed file in a different location. Would like use Spring integration for the same. I am trying to achieve this by the following code, but it is creating problem while routing based on file name. I am using JDK 8, Spring 5
.<File, Boolean>route(new Function<File, Boolean>() {
#Override
public Boolean apply(File f) {
return f.getName().contains("individual");
}
}, m -> m
.subFlowMapping(true, sf -> sf.gateway(individualProcessor()))
.subFlowMapping(false, sf -> sf.gateway(firmProcessor()))
)
Exception
Caused by: java.lang.IllegalArgumentException: Found ambiguous parameter type [interface java.util.function.Function] for method match: [public default <V> java.util.function.Function<V, R> java.util.function.Function.compose(java.util.function.Function<? super V, ? extends T>), public static <T> java.util.function.Function<T, T> java.util.function.Function.identity(), public java.lang.Boolean com.xxx.thirdpatysystem.config.IntegrationConfig$1.apply(java.io.File)]
at org.springframework.util.Assert.isNull(Assert.java:155) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.integration.util.MessagingMethodInvokerHelper.findHandlerMethodsForTarget(MessagingMethodInvokerHelper.java:843) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:362) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:231) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:225) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.handler.MethodInvokingMessageProcessor.<init>(MethodInvokingMessageProcessor.java:60) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.router.MethodInvokingRouter.<init>(MethodInvokingRouter.java:46) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.dsl.IntegrationFlowDefinition.route(IntegrationFlowDefinition.java:1922) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.dsl.IntegrationFlowDefinition.route(IntegrationFlowDefinition.java:1895) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
even I have tried below
.<File, Boolean>route(f -> f.getName().contains("individual"), m -> m
.subFlowMapping(true, sf -> sf.gateway(individualProcessor()))
.subFlowMapping(false, sf -> sf.gateway(firmProcessor()))
)
Exception
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'thirdpatysystemFlow' threw exception; nested exception is java.lang.UnsupportedOperationException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:579) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
... 17 common frames omitted
Caused by: java.lang.UnsupportedOperationException: null
at org.springframework.integration.dsl.StandardIntegrationFlow.configure(StandardIntegrationFlow.java:89) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.dsl.IntegrationFlowDefinition.gateway(IntegrationFlowDefinition.java:2172) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.integration.dsl.IntegrationFlowDefinition.gateway(IntegrationFlowDefinition.java:2151) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
Entire code snippet is below
import java.io.File;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.dsl.channel.MessageChannels;
import org.springframework.integration.file.FileReadingMessageSource;
import org.springframework.integration.file.FileWritingMessageHandler;
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
import org.springframework.integration.file.filters.ChainFileListFilter;
import org.springframework.integration.file.filters.RegexPatternFileListFilter;
import org.springframework.integration.zip.splitter.UnZipResultSplitter;
import org.springframework.integration.zip.transformer.UnZipTransformer;
import org.springframework.integration.zip.transformer.ZipResultType;
import org.springframework.messaging.MessageHandler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* #author dpoddar
*
*/
#Configuration
#EnableIntegration
public class IntegrationConfig {
#Value("${input.directory}")
private String inputDir;
#Value("${outputDir.directory}")
private String outputDir;
#Value("${input.scan.frequency: 100}")
private long scanFrequency;
#Bean
public MessageSource<File> inputFileSource() {
FileReadingMessageSource src = new FileReadingMessageSource();
src.setDirectory(new File(inputDir));
src.setAutoCreateDirectory(true);
ChainFileListFilter<File> chainFileListFilter = new ChainFileListFilter<>();
chainFileListFilter.addFilter(new AcceptOnceFileListFilter<>() );
chainFileListFilter.addFilter(new RegexPatternFileListFilter("(?i)^.+\\.zip$"));
src.setFilter(chainFileListFilter);
return src;
}
#Bean
public UnZipTransformer unZipTransformer() {
UnZipTransformer unZipTransformer = new UnZipTransformer();
unZipTransformer.setExpectSingleResult(false);
unZipTransformer.setZipResultType(ZipResultType.FILE);
//unZipTransformer.setWorkDirectory(new File("/usr/tmp/uncompress"));
unZipTransformer.setDeleteFiles(true);
return unZipTransformer;
}
#Bean
public UnZipResultSplitter splitter() {
UnZipResultSplitter splitter = new UnZipResultSplitter();
return splitter;
}
#Bean
public DirectChannel outputChannel() {
return new DirectChannel();
}
#Bean
public MessageHandler fileOutboundChannelAdapter() {
FileWritingMessageHandler adapter = new FileWritingMessageHandler(new File(outputDir));
adapter.setDeleteSourceFiles(true);
adapter.setAutoCreateDirectory(true);
adapter.setExpectReply(false);
return adapter;
}
#Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
return executor;
}
#Autowired
DirectChannel outputChannel;
#Autowired
MessageHandler fileOutboundChannelAdapter;
#Bean
public IntegrationFlow individualProcessor() {
return flow -> flow.handle("thirdpatysystemprocessor","processfile").channel(outputChannel).handle(fileOutboundChannelAdapter);
}
#Bean
public IntegrationFlow firmProcessor() {
return flow -> flow.handle("thirdpatysystemprocessor","processfile").channel(outputChannel).handle(fileOutboundChannelAdapter);
}
#Bean
public IntegrationFlow thirdpatysystemAgentDemographicFlow() {
return IntegrationFlows
.from(inputFileSource(), spec -> spec.poller(Pollers.fixedDelay(scanFrequency,TimeUnit.SECONDS)))
.transform(unZipTransformer())
.split(splitter())
.channel(MessageChannels.executor(taskExecutor()))
.<File, Boolean>route(new Function<File, Boolean>() {
#Override
public Boolean apply(File f) {
return f.getName().contains("individual");
}
}, m -> m
.subFlowMapping(true, sf -> sf.gateway(individualProcessor()))
.subFlowMapping(false, sf -> sf.gateway(firmProcessor()))
)
.aggregate()
/*.handle("thirdpatysystemprocessor","processfile")
.channel(outputChannel())
.handle(fileOutboundChannelAdapter())*/
.get()
;
}
}
The java.lang.IllegalArgumentException: Found ambiguous parameter type [interface java.util.function.Function] has been fixed in the Spring Integration 5.0.5: https://jira.spring.io/browse/INT-4456. So, now with an explicit Function impl we do this:
MethodInvokingRouter methodInvokingRouter = isLambda(router)
? new MethodInvokingRouter(new LambdaMessageProcessor(router, payloadType))
: new MethodInvokingRouter(router, ClassUtils.FUNCTION_APPLY_METHOD);
We explicitly point to the apply() method.
The re-use of existing IntegrationFlow beans in the sub-flows (gateway()) has been fixed in version 5.0.4: https://jira.spring.io/browse/INT-4434
So, what you need is just to upgrade your project to the latest dependencies. In particular Spring Integration 5.0.7: https://spring.io/projects/spring-integration#learn

Spring Integration HTTP Outbound Gateway Post Request with Java DSL

I am trying to consume a rest service and receive a json back and convert it to a list of objects. but I am receiving the below erorr. I am new to EIP and there aren't many tutorials for doing this in java dsl. I have configured 2 channels, one for sending a request and one for receiving the payload back.
Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'httpPostAtms' is expected to be of type 'org.springframework.messaging.MessageChannel' but was actually of type 'org.springframework.integration.dsl.StandardIntegrationFlow'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:378)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:89)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:46)
at org.springframework.integration.gateway.MessagingGatewaySupport.getRequestChannel(MessagingGatewaySupport.java:344)
at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:433)
at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceive(MessagingGatewaySupport.java:422)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:474)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:429)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:420)
at org.springframework.integration.gateway.GatewayCompletableFutureProxyFactoryBean.invoke(GatewayCompletableFutureProxyFactoryBean.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy70.getAllAtms(Unknown Source)
at com.backbase.atm.IngAtmApplication.main(IngAtmApplication.java:25)
I am using SI with Spring Boot
#IntegrationComponentScan
#Configuration
#EnableIntegration
#ComponentScan
public class InfrastructorConfig {
#Bean
public PollableChannel requestChannel() {
return new PriorityChannel() ;
}
#Bean
public MessageChannel replyChannel() {
return new DirectChannel() ;
}
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata poller() {
return Pollers.fixedRate(500).get();
}
#Bean
public IntegrationFlow httpPostAtms() {
return IntegrationFlows.from("requestChannel")
.handle(Http.outboundGateway("https://www.ing.nl/api/locator/atms/")
.httpMethod(HttpMethod.POST)
.extractPayload(true))
.<String, String>transform(p -> p.substring(5))
.transform(Transformers.fromJson(Atm[].class))
.channel("responseChannel")
.get();
}
}
The Gateway
package com.backbase.atm.service;
import java.util.List;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.messaging.handler.annotation.Payload;
import com.backbase.atm.model.Atm;
#MessagingGateway
public interface IntegrationService {
#Gateway(requestChannel = "httpPostAtms")
#Payload("new java.util.Date()")
List<Atm> getAllAtms();
}
Application Start
package com.backbase.atm;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import com.backbase.atm.service.IntegrationService;
#SpringBootApplication
public class IngAtmApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(IngAtmApplication.class, args);
ctx.getBean(IntegrationService.class).getAllAtms();
ctx.close();
}
You have to use requestChannel bean name in the gateway definition. Right now you have there an IntegrationFlow bean name, but that is wrong.
Always remember that everything in Spring Integration are connected via channels.

Resources