Total Pageviews

2019/02/08

[Spring] Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException

Problem
I have a  configuration which provide more than one implementations for a bean:
package demo.config;

import org.apache.http.auth.UsernamePasswordCredentials;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
public class WebServicesClientConfig {

    @Value("${webservice.username}")
    private String userName;

    @Value("${webservice.password}")
    private String password;

    @Bean (name = "webServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate() {
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(jaxb2Marshaller());
        webServiceTemplate.setUnmarshaller(jaxb2Marshaller());

        webServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return webServiceTemplate;
    }
    
    @Bean (name = "oq2WebServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller2() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind2");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate oq2WebServiceTemplate() {
        WebServiceTemplate oq2WebServiceTemplate = new WebServiceTemplate();
        oq2WebServiceTemplate.setMarshaller(jaxb2Marshaller2());
        oq2WebServiceTemplate.setUnmarshaller(jaxb2Marshaller2());

        oq2WebServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return oq2WebServiceTemplate;
    }

    @Bean
    public HttpComponentsMessageSender httpComponentsMessageSender() {
        HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
        httpComponentsMessageSender.setCredentials(usernamePasswordCredentials());
        return httpComponentsMessageSender;
    }

    @Bean
    public UsernamePasswordCredentials usernamePasswordCredentials() {
        return new UsernamePasswordCredentials(userName, password);
    }

}


The client bean looks like:

package demo.client;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.ws.client.core.WebServiceTemplate;

@Component
public class OiClient {

    @Autowired
    @Qualifier("webServiceTemplate")
    private WebServiceTemplate webServiceTemplate;
    
    public Response getInfoByIdno() {
        // ignore details
    }

}

But as I start up spring boot, it throws the following exception:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oiService': Unsatisfied dependency expressed through field 'oiClient'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oiClient': Unsatisfied dependency expressed through field 'webServiceTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.ws.client.core.WebServiceTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=webServiceTemplate)}
 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1135) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]


How-To
The configuration class should be fixed as bellows:
package demo.config;

import org.apache.http.auth.UsernamePasswordCredentials;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
public class WebServicesClientConfig {

    @Value("${webservice.username}")
    private String userName;

    @Value("${webservice.password}")
    private String password;

    @Bean
    @Qualifier("webServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate() {
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(jaxb2Marshaller());
        webServiceTemplate.setUnmarshaller(jaxb2Marshaller());

        webServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return webServiceTemplate;
    }
    
    @Bean
    @Qualifier("oq2WebServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller2() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind2");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate oq2WebServiceTemplate() {
        WebServiceTemplate oq2WebServiceTemplate = new WebServiceTemplate();
        oq2WebServiceTemplate.setMarshaller(jaxb2Marshaller2());
        oq2WebServiceTemplate.setUnmarshaller(jaxb2Marshaller2());

        oq2WebServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return oq2WebServiceTemplate;
    }

    @Bean
    public HttpComponentsMessageSender httpComponentsMessageSender() {
        HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
        httpComponentsMessageSender.setCredentials(usernamePasswordCredentials());
        return httpComponentsMessageSender;
    }

    @Bean
    public UsernamePasswordCredentials usernamePasswordCredentials() {
        return new UsernamePasswordCredentials(userName, password);
    }

}


Reference
[1] https://www.logicbig.com/tutorials/spring-framework/spring-core/inject-bean-by-name.html

2019/02/07

[Java] How to do IP validation in Java?

Problem
How to do IP validation in Java?

How-To
Here has sample code:
    import lombok.Data;
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Pattern;

    @Data
    public class Param {
        
        @NotNull(message = "請提供性別")
        private String gender;
        
        @NotNull(message = "請提供呼叫者 IP address")
        @Pattern(regexp = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", 
                 message = "呼叫者 IP address 不合法")
        private String srcIp;
    }

Reference
[1] https://stackoverflow.com/a/14877281/6314840

2019/02/06

[Spring] How to use shedlock in spring framework?

Problem
Owing to my web application will deploy to a cluster, so I need to find a solution to prevent concurrent execution of scheduled Spring tasks.


Here has a short example to demo how to use shedlock.


How-To
Add dependencies in pom.xml
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-spring</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-provider-jdbc-template</artifactId>
            <version>1.0.0</version>
        </dependency>


Create table for shedlock
CREATE TABLE MY_BATCH_LOCK(
    name VARCHAR(64),
    lock_until TIMESTAMP(3) NULL,
    locked_at TIMESTAMP(3) NULL,
    locked_by  VARCHAR(255),
    PRIMARY KEY (name)
)



Add configuration in your spring boot application
package demo.config;

import java.time.Duration;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import net.javacrumbs.shedlock.spring.ScheduledLockConfiguration;
import net.javacrumbs.shedlock.spring.ScheduledLockConfigurationBuilder;

@Configuration
public class ShedlockConfig {
    
    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource, "MY_BATCH_LOCK");
    }

    @Bean
    public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
        return ScheduledLockConfigurationBuilder
                .withLockProvider(lockProvider)
                .withPoolSize(10)
                .withDefaultLockAtMostFor(Duration.ofMinutes(10))
                .build();
    }
    
}


Usage:
    private static final int TEN_MIN = 10 * 60 * 1000;

    @Scheduled(cron = "0 0 1 * * ?")
    @SchedulerLock(name = "mySchedulerTask", lockAtMostFor = TEN_MIN, lockAtLeastFor = TEN_MIN)
    public void execute() {
    }


2019/02/05

[Spring] org.springframework.ws.client.WebServiceIOException: I/O error: Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out

Problem
When I try to call web service, I get this SocketTimeoutException exception:
org.springframework.ws.client.WebServiceIOException: I/O error: Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:561)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:383)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:373)
    at gov.npa.antifraud.agent.web.service.BankSchedulerService.sendBankDataRequest(BankSchedulerService.java:211)
    at gov.npa.antifraud.agent.web.WebAgentApplication.lambda$0(WebAgentApplication.java:22)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:781)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243)
    at gov.npa.antifraud.agent.web.WebAgentApplication.main(WebAgentApplication.java:16)
    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.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735)
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1587)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
    at org.springframework.ws.transport.http.HttpUrlConnection.getResponseCode(HttpUrlConnection.java:143)
    at org.springframework.ws.transport.http.AbstractHttpSenderConnection.hasError(AbstractHttpSenderConnection.java:53)
    at org.springframework.ws.client.core.WebServiceTemplate.hasError(WebServiceTemplate.java:673)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:607)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
    ... 16 more


How to extend timed out value?


The Web Service client configuration is:
package demo.web.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
public class WsClientConfig {
    
    private String defaultURI = "http://localhost:8080/services";
    
    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        // ignored implementation details        
        return jaxb2Marshaller;
    }
    
    @Bean
    public WebServiceTemplate webServiceTemplate() {
        WebServiceTemplate wsTemplate = new WebServiceTemplate();
        wsTemplate.setMarshaller(jaxb2Marshaller());
        wsTemplate.setUnmarshaller(jaxb2Marshaller());
        wsTemplate.setDefaultUri(defaultURI);
        
        return wsTemplate;
    }
}



How-To
The default values to connection timeout and read timeout in spring framework is 1 minute.



If I would like to extend to 2 minutes, the WsClientConfig should be modified as bellows:
package demo.web.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
public class WsClientConfig {
    
    private String defaultURI = "http://localhost:8080/services";
    
    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        // ignored implementation details        
        return jaxb2Marshaller;
    }
    
    @Bean
    public WebServiceTemplate webServiceTemplate() {
        WebServiceTemplate wsTemplate = new WebServiceTemplate();
        wsTemplate.setMarshaller(jaxb2Marshaller());
        wsTemplate.setUnmarshaller(jaxb2Marshaller());
        wsTemplate.setDefaultUri(defaultURI);
        wsTemplate.setMessageSender(webServiceMessageSender());
        
        return wsTemplate;
    }
    
    @Bean
    public WebServiceMessageSender webServiceMessageSender() {
      HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
      // timeout for creating a connection
      httpComponentsMessageSender.setConnectionTimeout(120 * 1000);
      // when you have a connection, timeout the read blocks for
      httpComponentsMessageSender.setReadTimeout(120 * 1000);

      return httpComponentsMessageSender;
    }
}