5

Below is my Spring Java Configuration class. I would like to have spring xml for it. The confusion I have is, how to convert @Bean HttpClient to xml (do I need to use factory method? )

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.net.ssl.SSLContext;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import com.google.common.collect.Lists;

@Configuration
    public class RestClientConfig {

        @Bean
        public ClientHttpRequestFactory httpRequestFactory() throws GeneralSecurityException, IOException {
            return new HttpComponentsClientHttpRequestFactory(httpClient());
        }

        @Bean
        public HttpClient httpClient() throws GeneralSecurityException, IOException {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            TrustStrategy allTrust = new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            };

            SSLContext sslcontext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, allTrust).build();

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            return httpClient;
        }

        @Bean
        public RestTemplate restTemplate() throws GeneralSecurityException, IOException {
            RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
            List<ClientHttpRequestInterceptor> interceptors = Lists.newArrayList();
            interceptors.add(new RestAuthInterceptor());

            restTemplate.setInterceptors(interceptors);

            return restTemplate;
        }

    }

::EDIT:: This is what I did after getting help from Jose Luis Martin and MariuszS. XML File:

<bean id="httpClient" class="com.orbit.restclient.support.CustomHttpClientFactory" />

    <bean class="org.springframework.web.client.RestTemplate">
        <constructor-arg>               
            <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
                <constructor-arg ref="httpClient" />
            </bean>
        </constructor-arg>
        <property name="interceptors">
            <list>
                <bean class="com.orbit.restclient.support.RestAuthInterceptor" />
            </list>
        </property>
    </bean>

Custom Class:

public class CustomHttpClientFactory implements FactoryBean<HttpClient> {

    @Override
    public HttpClient getObject() throws Exception {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        // TODO: update code here to validate certificate. This code allows all certificates
        TrustStrategy allTrust = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
            }
        };

        SSLContext sslcontext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, allTrust).build();

        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        return httpClient;
    }

    @Override
    public Class<HttpClient> getObjectType() {
        return HttpClient.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}
5
  • 2
    It's definitely not obvious to convert that Java configuration to XML and I recommend you don't. Why do you want to? Commented Jan 8, 2014 at 20:27
  • I prepared POC using spring 3.2 with Java config. Now, I am asked to embed that in existing application (with all xml configuration). I am asked xml configuration (java config, may be later !!) Commented Jan 8, 2014 at 20:49
  • You can mix xml and Java configuration in one application... Commented Jan 8, 2014 at 20:52
  • Do you have some repo of this code available on the net for public ? Commented Jan 9, 2014 at 13:57
  • No, I do not have public repo for now. Commented Jan 10, 2014 at 17:48

2 Answers 2

4

Try with:

<bean id="httpClient" class="test.HttpClientFactoryBean" />

    <bean id="httpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
        <constructor-arg ref="httpClient"></constructor-arg>
    </bean>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="interceptors">
            <list>
                <bean class="RestAuthInterceptor" />
            </list>
        </property>
    </bean>

And

public class HttpClientFactoryBean extends AbstractFactoryBean<HttpClient> {

    @Override
    public Class<?> getObjectType() {
        return HttpClient.class;
    }

    @Override
    protected HttpClient createInstance() throws Exception {
         KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
         TrustStrategy allTrust = new TrustStrategy() {
             @Override
             public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                 return true;
             }
         };

         SSLContext sslcontext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, allTrust).build();

         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
         CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

         return httpClient;
    }

}
Sign up to request clarification or add additional context in comments.

Comments

3

Spring Java Configuration is much more easier to write and read, but if this is your requirement then look at something like this - this is more a concept like working solution :)

Solution with Factory and Method Injection

<beans>

    <bean name="httpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
        <constructor-arg value="httpClient"/>
    </bean>

    <bean id="httpClientFactory" class="my.custom.HttpClientFactory" scope="prototype">
        <lookup-method name="create" bean="httpClient"/>
    </bean>
    <bean name="httpClient" class="org.apache.http.client.HttpClient"/>

    <bean name="restTemplateFactory" class="my.custom.RestTemplateFactory" scope="prototype">
        <lookup-method name="create" bean="restTemplate"/>
    </bean>
    <bean name="restTemplate" class="org.springframework.web.client.RestTemplate"/>

</beans>

and example factory bean:

public class HttpClientFactory {

    public HttpClient create(){
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        TrustStrategy allTrust = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        };

        SSLContext sslcontext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, allTrust).build();

        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        return httpClient;
    }

}

This is also possible to use ServiceLocatorFactoryBean

3 Comments

+1 If you can't use @Bean configuration, you can use this or even a FactoryBean.
I think that this will not work as you are overriding the create method with a lookup-method that will never executed and a plain HttpClient will be inject at all.
This solution require scope="prototype", corrected. This should work, this is common pattern described in Spring Reference Documentation :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.