How to make Java ServiceActivator visible in JUnit Test?
I have started writing a test which imports some spring integration xmls via some Java Config files (ie, files set in the #ContextConfiguration). One of these xml files references a channel called pollerErrorChannel this is the input-channel to a ServiceActivator declared in a Java Class. When the test cranks up I get the following error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sftpInboundAdapterBusiness': Cannot create inner bean '(inner bean)#1fe8d51b' of type [org.springframework.integration.scheduling.PollerMetadata] while setting bean property 'pollerMetadata'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#1fe8d51b': Cannot create inner bean '(inner bean)#324dcd31' of type [org.springframework.integration.channel.MessagePublishingErrorHandler] while setting bean property 'errorHandler'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#324dcd31': Cannot resolve reference to bean 'pollerErrorChannel' while setting bean property 'defaultErrorChannel'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'pollerErrorChannel' available
Below in my test
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {PropertySourcesPlaceholderConfigurer.class,
SFTPSampleReceiver.class,
SampleIngestBusinessConfig.class,
SampleIngestConfig.class,
SessionFactoryConfig.class},
initializers = ConfigFileApplicationContextInitializer.class)
#TestPropertySource(locations={"/application.yml"})
public class BusinessSampleRecieverTests {
#Test
public void test() {
}
}
Segment from sample-ingest-business.xml which specifies pollerErrorChannel as a channel
<int-sftp:inbound-channel-adapter id="sftpInboundAdapterBusiness"
channel="sftpInboundBusiness"
session-factory="sftpSessionFactory"
local-directory="${sftp.localdirectory}/business-local"
filter="businessCompositeFilter"
remote-file-separator="/"
remote-directory="${sftp.directory}/business-sftp">
<int:poller cron="${sftp.cron}" max-messages-per-poll="1" error-channel="pollerErrorChannel"/>
</int-sftp:inbound-channel-adapter>
Here is The Java Class which specifies pollerErrorChannel as the InputChannel to a #ServiceActivator
#Slf4j
#MessageEndpoint
#Component
public class SFTPSampleReceiver {
#ServiceActivator(inputChannel = "pollerErrorChannel", outputChannel = "errorUploadChannel")
public Message<String> processInvalidSample(GenericMessage errorMessage) {
String error = ((Exception) errorMessage.getPayload()).getCause().toString();
String fileName = ((MessagingException) errorMessage.getPayload()).getFailedMessage().getHeaders()
.get("file_name").toString();
String directory = ((MessagingException) errorMessage.getPayload()).getFailedMessage().getHeaders()
.get("sample_type").toString() + "-sftp";
String shortFileName = fileName.replace(".xml", "");
String errorFile = shortFileName + "_error.txt";
log.debug(fileName + " Was invalid and rejected.");
final Message<String> message = MessageBuilder.withPayload(error).setHeader("error_file_name",
errorFile).setHeader("file_name", fileName).setHeader("short_file_name",
shortFileName).setHeader("directory", directory).build();
return message;
}
}
thanks
You have to declare that pollerErrorChannel bean.
With just a #ServiceActivator(inputChannel = "pollerErrorChannel" it will be already to late to have that channel auto-created. The <poller> is parsed and populated as a bean a bit earlier.
We might review the PollerParser to use MessagePublishingErrorHandler.setDefaultErrorChannelName() isntead of errorHandler.addPropertyReference("defaultErrorChannel", errorChannel); to let to resolve the channel late on demand.
Feel free to raise a JIRA on the matter!
Garys comment about adding < int:annotation-config/> to your XML worked
Related
So I've been trying to find out solution to this from long ! Any insights would help !
I am getting following error
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'routerConnectionFactory' defined in class path resource
[com/CONFIDENTIAL/event/processor/configuration/EventsConfiguration.class]: Unsatisfied dependency expressed through method 'routerConnectionFactory' parameter 0; nested exception is
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named
'actionRouterConnectionFactory' is expected to be of type 'org.apache.activemq.ActiveMQConnectionFactory' but
was actually of type 'org.springframework.cloud.sleuth.instrument.messaging.LazyTopicConnectionFactory'
Code snippet
#Bean(name = "routerConnectionFactory")
#Primary
public CachingConnectionFactory routerConnectionFactory(ActiveMQConnectionFactory actionRouterConnectionFactory ){
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setTargetConnectionFactory(actionRouterConnectionFactory);
return cachingConnectionFactory;
}
#Bean
public ActiveMQConnectionFactory actionRouterConnectionFactory(
#Value("${confidential.gateway.message.broker.url}") String brokerURL,
#Value("${confidential.router.message.broker.user.name}") String userName,
#Value("${confidential.router.message.broker.user.password}") String password,
#Value("true") Boolean alwaysSyncSend, RedeliveryPolicy defaultEntry,
#Value("${shared.amq.keystore.path:#{null}}") String keyStorePath,
#Value("${shared.amq.keystore.password:#{null}}") String keyStorePassword) throws Exception {
ActiveMQSslConnectionFactory targetConnectionFactory= new ActiveMQSslConnectionFactory();
targetConnectionFactory.setBrokerURL(brokerURL);
targetConnectionFactory.setUserName(userName);
targetConnectionFactory.setPassword(password);
if(!StringUtils.isEmpty(keyStorePath) && !StringUtils.isEmpty(keyStorePassword)){
targetConnectionFactory.setTrustStore(keyStorePath);
targetConnectionFactory.setTrustStorePassword(keyStorePassword);
}
targetConnectionFactory.setAlwaysSyncSend(alwaysSyncSend);
targetConnectionFactory.setRedeliveryPolicy(defaultEntry);
return targetConnectionFactory;
}
spring-cloud-sleuth-core : 2.2.6.RELEASE
spring-cloud-sleuth-zipkin : 2.2.6.RELEASE
active-mq-broker, active-mq-camel, client, jms-pool , open-wire-legacy, pool, spring : 5.15.13
other spring boot and related dependencies : 2.2.6.RELEASE
https://edwin.baculsoft.com/2019/07/error-overriding-bean-of-same-name-declared-in-class-path-resource-when-integrating-spring-cloud-sleuth-and-activemq-library/
Referred multiple articles on this issue (also on StackoverFlow), also tried disabling sleuth but didn't help !
Any clue ?
Your method signatures are looking for 'ActiveMQConnectionFactory'-- that is tightly coupled to ActiveMQ. Most likely, the intetion is to couple to JMS API instead. Change code to use javax.jms.ConnectionFactory instead. (ActiveMQConnectionFactory implements javax.jms.ConnectionFactory)
I try to a mailservice in Spring. I use Spring-Boot version 2.1.7.Release and amazon-sqs-java-messaging-lib version 1.0.8.
My code looks like:
#Service
#RequiredArgsConstructor
public class MailService {
private static final Logger logger = Logger.getLogger(MailService.class.getName());
private final AmazonSQS amazonSQS;
#Value("${aws.sqs.queue.mail}")
private final String sqsQueueMail;
public void sendMail(final SQSMailParams mailParams) {
final String queueUrl = amazonSQS.getQueueUrl(sqsQueueMail).getQueueUrl();
try {
final String messageBody = SQSMailParams.createSQSMailParams(mailParams, mailParams.getTemplateKey(), mailParams.getProcessId()).toJson();
final SendMessageRequest sendMessageRequest = new SendMessageRequest(queueUrl, messageBody);
sendMessageRequest.setMessageGroupId("TOLL-BOX-MAIL");
amazonSQS.sendMessage(sendMessageRequest);
logger.info("TOLL-BOX mail added to mail queue");
} catch (JsonProcessingException e) {
logger.error("Mail cannot be added to the mail queue: " + String.join(",", mailParams.recipients) + "." + e);
}
}
}
But i get the following failure by running the code.
2020-03-02 07:34:00.242 ERROR 10568 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of constructor in de.svg.tollbox.service.MailService required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
Disconnected from the target VM, address: '127.0.0.1:43565', transport: 'socket'
Process finished with exit code 1
Could someone tell me what im doing wrong thank you.
Remove final from sqsQueueMail.
#Value("${aws.sqs.queue.mail}")
private String sqsQueueMail;
That should fix your issue.
Somehow, with #RequiredArgsConstructor, the #Value annotation for the variable is not resolved which made the application to look for a bean of type String
Сreate lombok.config file in the root of project and add following line:
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
That will allow you to use #Value with final field and with #RequiredArgsConstructor
When I deploy 2 packages with Spring AMQP I get JMX error in the below code:
#Bean
public CachingConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(HOST);
connectionFactory.setBeanName("Test_123");
return connectionFactory;
}
I error Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.amqp.rabbit.connection:name=connectionFactory,type=CachingConnectionFactory
Full error stack:
https://pastebin.com/CdU3epMz
How I can set unique name for connectionFactory?
EDIT:
I also tried to place application.properties under src/main/java/resources this configuration:
spring.jmx.enabled=false
spring.datasource.jmx-enabled=false
spring.jmx.default-domain=ssds # JMX domain name.
spring.jmx.server=apiServer # MBeanServer bean name.
management.metrics.export.jmx.domain=metccriddcs # Metrics JMX domain name.
management.metrics.export.jmx.enabled=false # Whether exporting of metrics to JMX is enabled.
management.endpoints.jmx.exposure.exclude=*
But I get the same error.
The solution:
... implements ObjectNamingStrategy {
#Override
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
Class managedClass = AopUtils.getTargetClass(managedBean);
String domain = ClassUtils.getPackageName(managedClass);
Hashtable<String, String> properties = new Hashtable<>();
properties.put("type", ClassUtils.getShortName(managedClass));
properties.put("name", "asdsdsd");
// ensure the application name is included as a property in the object name
properties.put("app", "api");
return ObjectNameManager.getInstance(domain, properties);
}
}
I am facing a strange issue when I build the jar through Jenkins .
The WAR file created through Jenkins is unable to load the "Application.properties" file .
Meaning it is unable to inject anything in the "applicationProperties" field in the "ISellGenevaCacheClient.java" file - LINE 4
This issue is only happening when I build the WAR though Jenkins .
If I build the WAR normally in Eclipse (by maven clean install) , it is able to inject value into "ApplicationProperties" in "ISellGenevaCacheClient.java" file .
My "Application.properties" file is present under src/main/resources
Below are the java files being used .
My ApplicationProperties.java
#Component
#ConfigurationProperties(locations ="classpath:application.properties", ignoreUnknownFields = false , prefix="prop")
public class ApplicationProperties {
private String algorithm;
public String getAlgorithm() {
return algorithm;
}
void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
}
EncryptionUtilitiesImpl.java
public class EncryptionUtilitiesImpl {
private ApplicationProperties applicationProperties;
public EncryptionUtilitiesImpl(ApplicationProperties appProp) { // Constructor
applicationProperties = appProp;
}
public String decryptString(final String cipherTextHex) {
byte[] key = formEncryptionKeyArray(applicationProperties.getKeyProp()); // ---> Line 75 : Here , we are getting the applicationProperties as NULL
String decryptString = decryptStringFromHexWithMac(cipherTextHex, key);
return decryptString;
}
}
Utility.java
public class Utility {
public String decryptValue(String encryptedValue){
EncryptionUtilitiesImpl encryptionUtil = new EncryptionUtilitiesImpl(applicationProperties);
return encryptionUtil.decryptString(encryptedValue); // ---> Line 199
}
}
CacheClient.java
public class CacheClient {
#Inject
ApplicationProperties applicationProperties; //. --->. LINE 4
#Inject
Utility utility;
public void init(){
// -- Some code .. . . ..
Utility.decryptValue(applicationProperties.getAlgorithm())) // ---> Line 66
// --- Some code ... . . .
}}
I am getting the below NULL Pointer Exception because it is unable to inject any runtime object to 'applicationProperties' field in the "CacheClient.java" file -- LINE 4 .
Below is the Stack Trace :
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'CacheServiceImpl': Unsatisfied dependency expressed through field 'genevaInstance': Error creating bean with name 'ISellGenevaCacheClient': Invocation of init method failed; nested exception is java.lang.NullPointerException; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CacheClient': Invocation of init method failed; nested exception is java.lang.NullPointerException
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CacheClient': Invocation of init method failed; nested exception is java.lang.NullPointerException
Caused by: java.lang.NullPointerException: null
at com.test.util.EncryptionUtilitiesImpl.decryptString(EncryptionUtilitiesImpl.java:75)
at com.test.util.Utility.decryptValue(Utility.java:199)
at com.test.salesinterface.service.integration.geneva.cache.CacheClient.init(CacheClient.java:66)
I am really stuck here . Please Help .
I´m setting a bean for a spring boot application and I get the following error, can you please help me? I am not sure whether MyDataSource class is correct and whether something is missing within the application.properties
Many thanks in advance.
2017-07-22 13:50:33.752 WARN 6872 --- [ost-startStop-1]
ationConfigEmbeddedWebApplicationContext : Exception encountered during
context initialization - cancelling refresh attempt:
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name
'org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
2017-07-22 13:50:33.780 ERROR 6872 --- [ost-startStop-1] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
MyDataSource class:
public class MyDataSource {
private static final String driverClassName = "org.postgresql.Driver";
private static final String url = "jdbc:postgresql://mydbinstance3.ckvnevtnxxbs.us-west-2.rds.amazonaws.com:5432/postgres";
private static final String dbUsername = "OnFocus";
private static final String dbPassword = "G0nk0p0rr0";
private static DataSource dataSource;
public static void main(String[] args) throws Exception {
dataSource = getDataSource();
// JdbcTemplate template = new JdbcTemplate(dataSource); // constructor
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(dataSource);
System.out.println(dataSource.getClass());
}
public static DriverManagerDataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(dbUsername);
dataSource.setPassword(dbPassword);
return dataSource;
}
}
Build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.3.RELEASE")
classpath 'io.spring.gradle:dependency-management-plugin:0.6.1.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'war'
version = '1.0-SNAPSHOT'
buildDir = 'target'
jar {
baseName = rootProject.name
}
war {
baseName = 'myapp'
version = '1.0.0'
}
repositories {
jcenter()
maven { url "http://repo.spring.io/libs-snapshot" }
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa:1.2.5.RELEASE")
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("org.postgresql:postgresql:9.4-1201-jdbc41")
compile("org.springframework:spring-jdbc:4.2.4.RELEASE")
compile("com.fasterxml.jackson.core:jackson-databind")
compile("org.liquibase:liquibase-core:3.3.3")
compile("org.springframework.boot:spring-boot-starter-data-mongodb")
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
compile("org.springframework.boot:spring-boot-starter-web")
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testCompile("junit:junit")
}
bootRepackage {
mainClass = 'theproject.src.main.java.tutorialDatabaseServer.Application'
}
Application.properties:
server.port=8081
spring.datasource.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://mydbinstance3.ckvnevtnxxbs.us-west-
2.rds.amazonaws.com:5432/postgres
spring.datasource.username=OnFocus
spring.datasource.password=G0nk0p0rr0
liquibase.change-log=classpath:/db/changelog-master.xml
liquibase.enabled=true
Application class:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
You are enabling the use of liquibase in your properties file
liquibase.enabled=true
Have you intentionally activated it ? coz i dont see the liquibase dependency and the change log file .
Try to comment or remove ( if are not using liquibase ) these lines
liquibase.change-log=classpath:/db/changelog-master.xml
liquibase.enabled=true
I guess you are note using liquibase, when you put a liquibase properties spring de is trying to instanciate a liquibase bean . so if you don't need it , don't use it .