Injecting List with Spring from yaml

In my recent project, I need to fill a list from configuration file. With my old habits I just tried to use @Value annotation and my code just broke. Here is what I’ve tried first:

application.yaml:

segment:
  list:
    - SEG1
    - SEG2

AppRunner.java:

@Component
public class AppRunner implements ApplicationRunner {

    @Value("${segment.list}")
    private List<String> segmentList;

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        segmentList.forEach(segment -> System.out.println(segment));
    }

}

However, it just exploded like below:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'segment.list' in string value "${segment.list}"
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:204) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:808) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1027) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	... 23 common frames omitted

After that, I used a workaround for this problem and solve the issue with below annotation style on segmentList and application.yaml:

    @Value("#{'${segment.list}'.split(',')}")
    private List<String> segmentList;

application.yaml:

segment:
  list: SEG1,SEG2

I was basically, splitting a String with comma. It seems fine when I run the application. However, when I run my unit tests I get below error:

Unit test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = App.class)
public class AppRunnerTest {

    @Autowired
    private AppRunner appRunner;

    @Test
    public void testRun() throws Exception {
        appRunner.run(null);
    }

}

Exception:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'segment.list' in string value "#{'${segment.list}'.split(',')}"
 at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
 at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
 at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:204)
 at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178)
 at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
 at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:808)
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1027)
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
 ... 46 more

I’ve looked at a lot of annotation like @TestPropertySource and tried a lot of methods like injecting PropertyPlaceHolder to my test classes to run unit tests with this way but couldn’t manage it. The application context doesn’t aware of my properties because different application context is created when I run tests. At the end, I found this issue on Spring’s Jira system. That was the same issue I had and it guided me to @ConfigurationProperties annotation. And fortunately, I was using Spring Boot and already have this annotation in my path. With this guidance I add a new configuration class, changed application.yaml to list style again and get my list from configurations with the help of @EnableConfigurationProperties annotation at injection:

Config class:

@Configuration
@ConfigurationProperties(prefix = "segment")
public class SegmentListConfig {

    private List<String> list;

    SegmentListConfig() {
        this.list = new ArrayList<>();
    }

    public List<String> getList() {
        return this.list;
    }

}

Runner class:

@Component
@EnableConfigurationProperties
public class AppRunner implements ApplicationRunner {

    @Autowired
    private SegmentListConfig segmentListConfig;

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        segmentListConfig.getList().forEach(segment -> System.out.println(segment));
    }

}

application.yaml:

segment:
  list:
    - SEG1
    - SEG2

When I dig into a little bit, I found that @ConfigurationProperties can do more. Here is a nice little blog post about how to use it.

I simulated my steps in different commits at this repository. You can check whole working code and not working codes from there.

Developers Rock!!!

Advertisements
Posted in Java | Tagged , , , , , , , , , , , , | Leave a comment

Adding New Library To Maven Repository

Sometimes, you find a custom library on the internet, or create it by yourself for something special. Probably, you cannot find those kind of libraries in maven repositories and add your maven dependencies for your maven based projects. But, if you need special library in your maven dependencies to package your project, there is a maven feature that enables you to install this library to your local maven repository.

For example I will show you how to add Oracle jdbc driver to your repository. I have Oracle XE in my computer and if you go to this path “C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib” you will find Oracle drivers for your use. Or you can just download it from on the internet. Now let’s open a console and write this command:

mvn install:install-file -Dfile="C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib\ojdbc6.jar" -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0 -Dpackaging=jar

After that you will see a screen like below:
Maven Install Repository

Then you can add this library to your pom.xml like below. Be careful that groupId, artifactId and version are identical with the command above.

<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0</version>
</dependency>

Developers Rock!!!

Posted in Java | Tagged , , , , , | Leave a comment

How To Authenticate Http Level Provided Web Service

In this post, I will give you a code for to consume web services with protected http basic authentication. I pretend that, there is a web service called SimpleWebService and it has a method that called getDummy. Here is the code:

public class Test {

	public static void main(String[] args) {
		SimpleWebServiceImplService service = new SimpleWebServiceImplService();

		SimpleWebService simpleWebService = service.getSimpleWebServicePort();

		((BindingProvider) simpleWebService).getRequestContext().put(BindingProvider.USERNAME_PROPERTY,"USERNAME");
		((BindingProvider) simpleWebService).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,"PASSWORD");

		SimpleWebServiceRequest request = new SimpleWebServiceRequest();
		SimpleWebServiceResponse response = simpleWebService.getDummy(request);

		System.out.println(response);
	}
}

We just put necessary username and password parameters to our request context and that’s all. This the only operation that we have done different from regular web service call.

Developer’s rock!!!

Posted in Java | Tagged , , , , , , | Leave a comment

Web Service Application Level Authentication

In some situations we need to protect our private data, so we may want to use authentication mechanism for our web services. In this writing, I will give you an example to how you can create web service authentication level at application level, and how you can call this kind of web services.

First of all, we need to create a web service. I am not going to deploy the application to a web server like Weblogic or Tomcat. I will use embedded web server in Java, however you can deploy your applications freely to other web servers.

I will give a brief explanation of classes on the top of code and detailed explanations will be inside the code with comments.

Here is the project structure:

Ws Project Structure

Below interface will be used as a web service endpoint interface. Implementation will check this interface for methods.

package com.aykutakin.ws;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface SampleWebService {
	
	@WebMethod
	String getDummy(String msg);
	
}

Below class handles the request. Main implementation will be done in this class. Note that endpointInterface attribute of WebService annotation shows exactly where SampleWebService interface is.

package com.aykutakin.ws;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

@WebService(endpointInterface = "com.aykutakin.ws.SampleWebService")
public class SampleWebServiceImpl implements SampleWebService {

	// We can get request's message context using WebServiceContext
	@Resource
	private WebServiceContext webServiceContext;

	// This method must be implemented for the interface
	@Override
	public String getDummy(String msg) {

		// Get message context
		MessageContext messageContext = webServiceContext.getMessageContext();

		// Authentication information will be in request header.
		// So we extract the information from message request.
		Map<String, List<String>> reqHeaders = (Map<String, List<String>>) messageContext.get(MessageContext.HTTP_REQUEST_HEADERS);

		// Get header attributes
		String username = reqHeaders.get("Username").get(0);
		String password = reqHeaders.get("Password").get(0);

		// Check validity of information.
		// Probably you will need a proper authentication mechanism rather than hardcoded strings.
		// I used literal string equals method to run away from null check.
		if ("user1".equals(username) && "1111".equals(password)) {
			return "Successful Dummy String With Message: " + msg;
		}

		return "Unknown User!";
	}

}

Finally, we publish our application to server with using below code.

package com.aykutakin.ws;

import javax.xml.ws.Endpoint;

// This class is going to publish our web service to http server
public class SampleWebServiceEndpoint {
	
    public static void main(String[] args) {
	    Endpoint.publish("http://localhost:9999/ws/dummy", new SampleWebServiceImpl());
    }
    
}

After you make ready these classes, run the project. If you made the implementation right, you can see the web service wsdl in browser. Just check this address:

http://localhost:9999/ws/dummy?wsdl

If you see the wsdl then you are ready to call the web service. I created a client jar using this utility. Later that, I wrote below class for web service call.

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.MessageContext;

import com.aykutakin.ws.SampleWebService;
import com.aykutakin.ws.SampleWebServiceImplService;

public class Test {

	public static void main(String[] args) {
		SampleWebServiceImplService service = new SampleWebServiceImplService();
		
		SampleWebService sampleWebService = service.getSampleWebServiceImplPort();

		// Request header is a map that keys are String, values are List
		// Put information to a proper map
		Map<String, List<String>> headers = new HashMap<String, List<String>>();
		headers.put("Username", Arrays.asList(new String[]{"user1"}));
		headers.put("Password", Arrays.asList(new String[]{"1111"}));

		// Put header map to message context's request header parameter
		((BindingProvider) sampleWebService).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers);

		System.out.println(sampleWebService.getDummy("HelloWorld"));
	}

}

You should see a message like that when you run the code:
WsSuccessMessage

If you have questions, you can ask me anytime. As soon as I’m available, I will try to reply.

Developers Rock!!!

Posted in Java | Tagged , , , , , , , | Leave a comment

Logging SOAP Web Service Request and Response

In this writing, I will talk about how to log soap request and response xml’s in Java. I used a free weather webservice as a sample for this post. I created a GlobalWeather.jar using JAX-WS from this wsdl. If you don’t know how to create client jar, you can check this post (You need to change the root folder from ‘com’ to ‘net’).

To log the webservice requests and responses, we need to change the handler resolver to our custom one. We are going to add our SOAPHandler implementation to the chain and that way, our logging handler will work before we send request and after we get response. During this times, we can easily log necessary information.

Firstly, I will show you the logging handler. We simply implement SOAPHandler interface for this purposes. There are 4 methods we need to implement:

  • close: This method will be called lastly. If we use some resources, we can return them to system in this method.
  • handleFault: If we face with a problem during the service call, we can log it in this method.
  • handleMessage: If there is no problem during the service call, this method will be called naturally. Both request text and response text will be handled in this method. We can discriminate outbound message with MessageContext.MESSAGE_OUTBOUND_PROPERTY property.
  • getHeaders: It returns the QNames of the outer element of each SOAP header that the handler understands.

Below there is an implementation of SOAPHandler. Note that, handling methods return ‘true’ as a parameter. If you return ‘false’, you will face with an exception.

package com.webservicecaller;

import java.io.IOException;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class JaxWsLoggingHandler implements SOAPHandler<SOAPMessageContext> {

	@Override
	public void close(MessageContext arg0) {
	}

	@Override
	public boolean handleFault(SOAPMessageContext arg0) {
		SOAPMessage message = arg0.getMessage();
		try {
			message.writeTo(System.out);
		} catch (SOAPException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return true;
	}

	@Override
	public boolean handleMessage(SOAPMessageContext arg0) {
		SOAPMessage message = arg0.getMessage();
		boolean isOutboundMessage = (Boolean) arg0.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		if (isOutboundMessage) {
			System.out.println("OUTBOUND MESSAGE\n");

		} else {
			System.out.println("INBOUND MESSAGE\n");
		}
		try {
			message.writeTo(System.out);
		} catch (SOAPException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return true;
	}

	@Override
	public Set<QName> getHeaders() {
		return null;
	}

}

And below, you can find our Handler Resolver and how we add our logging handler to chain.

package com.webservicecaller;

import java.util.ArrayList;
import java.util.List;

import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;

public class JaxWsHandlerResolver implements HandlerResolver {

	@SuppressWarnings("rawtypes")
	@Override
	public List<Handler> getHandlerChain(PortInfo arg0) {
		List<Handler> hchain = new ArrayList<Handler>();
		hchain.add(new JaxWsLoggingHandler());
		return hchain;
	}

}

Then our main class stands below. As you can see, we set service handler resolver to our custom one at line 10.

package com.webservicecaller;

import net.webservicex.GlobalWeather;
import net.webservicex.GlobalWeatherSoap;

public class Test {

	public static void main(String[] args) {
		GlobalWeather globalWeather = new GlobalWeather();
		globalWeather.setHandlerResolver(new JaxWsHandlerResolver());

		GlobalWeatherSoap globalWeatherSoap = globalWeather.getGlobalWeatherSoap();
		System.out.println(globalWeatherSoap.getWeather("Turkey", "Istanbul / Ataturk"));
	}
}

After we run this code, we can see the result like below in console screen:

Logging Console

EDIT: If you want the output as formatted, you can use below handleMessage method:

    @Override
    public boolean handleMessage(SOAPMessageContext arg0) {
        SOAPMessage message = arg0.getMessage();
        boolean isOutboundMessage = (Boolean) arg0.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (isOutboundMessage) {
            System.out.println("OUTBOUND MESSAGE");
        } else {
            System.out.println("INBOUND MESSAGE");
        }
        try {
            Source source = message.getSOAPPart().getContent();

            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            
            transformer.transform(source, new StreamResult(System.out));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

If you have question, you can ask me anytime. As soon as I’m available, I will try to reply.

Developers Rock!!!

Posted in Java | Tagged , , , , , , , , | 20 Comments

Creating WebService Client with WsImport (Jax-WS)

WsImport is a powerful way to create Java Classes for web services. It is supported by the jdk’s higher than 1.5. We can easily create web service clients using wsimport executable file that comes with jdk installation. Below command create necessary classes for sample wsdl:

"C:\Program Files\Java\jdk1.6.0_45\bin\wsimport" http://domainname/project/sample.wsdl

This is really simple example of wsimport. If you want, you can specify binding parameters, keep real java class files and give target directory as an option. You can find full options from Oracle documentations.

I created a script that takes folder name and wsdl location and then creates client jar file for the service. It uses below binding.xml to control necessary parameters.

<jaxb:bindings version="2.1"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jaxb:globalBindings generateElementProperty="false"/>
</jaxb:bindings>

And written script is below. You can put it into text file and rename it wim.cmd with locating at the same folder with binding.xml. After you run the file and supply necessary parameters, the jar file will be created as ready to use.

@ECHO OFF
SET /P SERVICE_NAME=Please enter service name:
SET /P SERVICE_WSDL=Please enter wsdl address:
if exist %SERVICE_NAME% echo Error, directory %SERVICE_NAME% already exists. && GOTO:EOF
echo.
echo.
echo Generating jar for service %SERVICE_NAME% STARTED
echo.
mkdir %SERVICE_NAME%
echo Getting wsdl: %SERVICE_WSDL%
echo.
call "%JAVA_HOME%\bin\wsimport" -keep -b binding.xml -d %SERVICE_NAME% %SERVICE_WSDL%
IF ERRORLEVEL = 1 echo Error importing WSDL. && rd /s /q %SERVICE_NAME% && GOTO:EOF
cd %SERVICE_NAME%
echo Generating %SERVICE_NAME%.jar
echo.
"%JAVA_HOME%\bin\jar" cf ..\%SERVICE_NAME%.jar com
cd ..
rd /s /q %SERVICE_NAME%
echo Done.
pause

As you see in the code, JAVA_HOME variable must be already set in the system. You can change JAVA_HOME variable with absolute or relative path of the jdk installation to run given code. You may also need to change the root folder while creating jar file at line 17. I just wrote ‘com’ for root folder, but this may change according to service (for example I saw a lot of ‘net’ root folder while looking for free web services).

Developers Rock!!!

Posted in Java | Tagged , , , , , , , , | Leave a comment

XSD to Java Class with XJC

With the jdk version of 1.6 and later, we can easily create java classes from xsd using XJC(xml java compiler). In this post, I will give you a quick example to use ‘xjc’ to create java classes. Below I have a really basic xsd sample and I am going to create java classes using this definitions.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
  <xs:element name="employee" type="employee"/>
 
  <xs:complexType name="employee">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="department" type="department"/>
      <xs:element name="email" type="xs:string" minOccurs="0"/>
      <xs:element name="phone" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="id" type="xs:int" use="required"/>
  </xs:complexType>
 
  <xs:complexType name="department">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="manager" type="xs:string"/>
      <xs:element name="location" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="id" type="xs:int" use="required"/>
  </xs:complexType>

</xs:schema>

In this example I have an employee class with some basic variables. Employee also has a relation with department, which is an another complex type defined in the xsd.

When I want to create java classes, I simply execute below command:

"C:\Program Files\Java\jdk1.6.0_45\bin\xjc" -d target -p com.myproject.jaxb.beans sample.xsd

I run this command in the folder of ‘sample.xsd’. Because of that, I referred to full path of xjc. ‘xjc.exe’ can be found on where you installed jdk. Optionally, you can add jdk binaries to your path variable to simplify the usage of java built in binaries.

Now I want to mention about the input parameters that I used. ‘-d’ option specifies the output directory. If this directory not exist, command will prompt an error message to console. ‘-p’ is the another optional parameter to create a Java style folder presentation. If you do not use both ‘-d’ and ‘-p’ options, a folder called ‘generated’ will be created and all the files will be in that folder. Otherwise classes will be located according to your parameters.

You can find other options with using ‘-help’. There are some interesting experimental features of xjc that you may want to explore. If you have any question, you can contact with me anytime.

Developers Rock!!!

Posted in Java | Tagged , , , , | Leave a comment