Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

and many more ....

Featured FREE Whitepapers

What's New Here?

jboss-drools-logo

Drools decision tables with Camel and Spring

As I’ve shown it in my previous post JBoss Drools are a very useful rules engine. The only problem is that creating the rules in the Rule language might be pretty complicated for a non-technical person. That’s why one can provide an easy way for creating business rules – decision tables created in a spreadsheet! In the following example I will show you a really complicated business rule example converted to a decision table in a spreadsheet. As a backend we will have Drools, Camel and Spring.To begin with let us take a look at our imaginary business problem. Let us assume that we are running a business that focuses on selling products (either Medical or Electronic). We are shipping our products to several countries (PL, USA, GER, SWE, UK, ESP) and depending on the country there are different law regulations   concerning the buyer’s age. In some countries you can buy products when you are younger than in others. What is more depending on the country from which the buyer and the product comes from and on the quantity of products, the buyer might get a discount. As you can see there is a substantial number of conditions needed to be fullfield in this scenario (imagine the number of ifs needed to program this). Another problem would be the business side (as usual). Anybody who has been working on a project knows how fast the requirements are changing. If one entered all the rules in the code he would have to redeploy the software each time the requirements changed. That’s why it is a good practice to divide the business logic from the code itself. Anyway, let’s go back to our example. To begin with let us take a look at the spreadsheets (before that it is worth taking a look at the JBoss website with precise description of how the decision table should look like): The point of entry of our program is the first spreadsheet that checks if the given user should be granted with the possibility of buying a product (it will be better if you download the spreadsheets and play with them from Too Much Coding’s repository at Bitbucket: user_table.xls and product_table.xls, or Github user_table.xls and product_table.xls): user_table.xls (tables worksheet)Once the user has been approved he might get a discount: product_table.xls (tables worksheet)product_table.xls (lists worksheet)As you can see in the images the business problem is quite complex. Each row represents a rule, and each column represents a condition. Do you remember the rules syntax from my recent post? So you would understand the hidden part of the spreadsheet that is right above the first visible row:The rows from 2 to 6 represent some fixed configuration values such as rule set, imports ( you’ve already seen that in my recent post) and functions. Next in row number 7 you can find the name of the RuleTable. Then in row number 8 you have in our scenario either a CONDITION or an ACTION – so in other words either the LHS or rhe RHS respectively. Row number 9 is both representation of types presented in the condition and the binding to a variable. In row number 10 we have the exact LHS condition. Row number 11 shows the label of columns. From row number 12 we have the rules one by one. You can find the spreadsheets in the sources. Now let’s take a look at the code. Let’s start with taking a look at the schemas defining the Product and the User. Person.xsd <?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:include schemaLocation="user.xsd"/><xsd:element name="Product"> <xsd:complexType> <xsd:sequence> <xsd:element name="Name" type="xsd:string"/> <xsd:element name="Type" type="ProductType"/> <xsd:element name="Price" type="xsd:double"/> <xsd:element name="CountryOfOrigin" type="CountryType"/> <xsd:element name="AdditionalInfo" type="xsd:string"/> <xsd:element name="Quantity" type="xsd:int"/> </xsd:sequence> </xsd:complexType> </xsd:element><xsd:simpleType name="ProductType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="MEDICAL"/> <xsd:enumeration value="ELECTRONIC"/> </xsd:restriction> </xsd:simpleType></xsd:schema> User.xsd <?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:include schemaLocation="product.xsd"/><xsd:element name="User"> <xsd:complexType> <xsd:sequence> <xsd:element name="UserName" type="xsd:string"/> <xsd:element name="UserAge" type="xsd:int"/> <xsd:element name="UserCountry" type="CountryType"/> <xsd:element name="Decision" type="DecisionType"/> <xsd:element name="DecisionDescription" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element><xsd:simpleType name="CountryType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="PL"/> <xsd:enumeration value="USA"/> <xsd:enumeration value="GER"/> <xsd:enumeration value="SWE"/> <xsd:enumeration value="UK"/> <xsd:enumeration value="ESP"/> </xsd:restriction> </xsd:simpleType><xsd:simpleType name="DecisionType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="ACCEPTED"/> <xsd:enumeration value="REJECTED"/> </xsd:restriction> </xsd:simpleType></xsd:schema> Due to the fact that we are using maven we may use a plugin that will convert the XSD into Java classes. part of the pom.xml <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>1.5</version> <executions> <execution> <id>xjc</id> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <packageName>pl.grzejszczak.marcin.drools.decisiontable.model</packageName> <schemaDirectory>${project.basedir}/src/main/resources/xsd</schemaDirectory> </configuration> </plugin> </plugins> </build> Thanks to this plugin we have our generated by JAXB classes in the pl.grzejszczak.marcin.decisiontable.model package. Now off to the drools-context.xml file where we’ve defined all the necessary beans as far as Drools are concerned: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://drools.org/schema/drools-spring http://drools.org/schema/drools-spring.xsd"><!-- Grid Node identifier that is registered in the CamelContext --> <drools:grid-node id="node1"/><drools:kbase id="productsKBase" node="node1"> <drools:resources> <drools:resource type="DTABLE" source="classpath:rules/product_table.xls"/> </drools:resources> </drools:kbase><drools:ksession id="productsKSession" name="productsKSession" type="stateless" kbase="productsKBase" node="node1"/><drools:kbase id="usersKBase" node="node1"> <drools:resources> <drools:resource type="DTABLE" source="classpath:rules/user_table.xls"/> </drools:resources> </drools:kbase><drools:ksession id="usersKSession" name="usersKSession" type="stateless" kbase="usersKBase" node="node1"/></beans> As you can see in comparison to the application context from the recent post there are some differences. First instead of passing the DRL file as the resource inside the knowledge base we are providing the Decision table (DTABLE). I’ve decided to pass in two seperate files but you can provide one file with several worksheets and access those worksheets (through the decisiontable-conf element). Also there is an additional element called node. We have to choose an implementation of the Node interface (Execution, Grid…) for the Camel route to work properly as you will see in a couple of seconds in the Spring application context file. applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.8.0.xsd"><import resource="classpath:drools-context.xml"/> <!-- Show Spring where to search for the beans (in which packages) --> <context:component-scan base-package="pl.grzejszczak.marcin.drools.decisiontable" /><camel:camelContext id="camelContext"> <camel:route id="acceptanceRoute"> <camel:from uri="direct:acceptanceRoute"/> <camel:to uri="drools:node1/usersKSession"/> </camel:route> <camel:route id="discountRoute"> <camel:from uri="direct:discountRoute"/> <camel:to uri="drools:node1/productsKSession"/> </camel:route> </camel:camelContext></beans> As you can see in order to access the Drools Camel Component we have to provide the node through which we will access the proper knowledge session. We have defined two routes – the first one ends at the Drools component that accesses the users knowledge session and the other the products knowledge session. We have a ProductService interface implementation called ProductServiceImpl that given an input User and Product objects pass them through the Camel’s Producer Template to two Camel routes each ending at the Drools components. The concept behind this product service is that we are first processing the User if he can even buy the software and then we are checking what kind of a discount he would receive. From the service’s point of view in fact we are just sending the object out and waiting for the response. Finally having reveived the response we are passing the User and the Product to the Financial Service implementation that will bill the user for the products that he has bought or reject his offer if needed. ProductServiceImpl.java package pl.grzejszczak.marcin.drools.decisiontable.service;import org.apache.camel.CamelContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import pl.grzejszczak.marcin.drools.decisiontable.model.Product; import pl.grzejszczak.marcin.drools.decisiontable.model.User;import static com.google.common.collect.Lists.newArrayList;/** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @Component("productServiceImpl") public class ProductServiceImpl implements ProductService {private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImpl.class);@Autowired CamelContext camelContext;@Autowired FinancialService financialService;@Override public void runProductLogic(User user, Product product) { LOGGER.debug("Running product logic - first acceptance Route, then discount Route"); camelContext.createProducerTemplate().sendBody("direct:acceptanceRoute", newArrayList(user, product)); camelContext.createProducerTemplate().sendBody("direct:discountRoute", newArrayList(user, product)); financialService.processOrder(user, product); }} Another crucial thing to remember about is that the Camel Drools Component requires the Command object as the input. As you can see, in the body we are sending a list of objects (and these are not Command objects). I did it on purpose since in my opinion it is better not to bind our code to a concrete solution. What if we find out that there is a better solution than Drools? Will we change all the code that we have created or just change the Camel route to point at our new solution? That’s why Camel has the TypeConverters. We have our own here as well. First of all let’s take a look at the implementation. ProductTypeConverter.java package pl.grzejszczak.marcin.drools.decisiontable.converter;import org.apache.camel.Converter; import org.drools.command.Command; import org.drools.command.CommandFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.grzejszczak.marcin.drools.decisiontable.model.Product;import java.util.List;/** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 30.01.13 * Time: 21:42 */ @Converter public class ProductTypeConverter {private static final Logger LOGGER = LoggerFactory.getLogger(ProductTypeConverter.class);@Converter public static Command toCommandFromList(List inputList) { LOGGER.debug("Executing ProductTypeConverter's toCommandFromList method"); return CommandFactory.newInsertElements(inputList); }@Converter public static Command toCommand(Product product) { LOGGER.debug("Executing ProductTypeConverter's toCommand method"); return CommandFactory.newInsert(product); } } There is a good tutorial on TypeConverters on the Camel website – if you needed some more indepth info about it. Anyway, we are annotating our class and the functions used to convert different types into one another. What is important here is that we are showing Camel how to convert a list and a single product to Commands. Due to type erasure this will work regardless of the provided type that is why even though we are giving a list of Product  and User, the toCommandFromList function will get executed. In addition to this in order for the type converter to work we have to provide the fully quallified name of our class (FQN) in the /META-INF/services/org/apache/came /TypeConverter file. TypeConverter pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter In order to properly test our functionality one should write quite a few tests that would verify the rules. A pretty good way would be to have input files stored in the test resources folders that are passed to the rule engine and then the result would be compared against the verified output (unfortunately it is rather impossible to make the business side develop such a reference set of outputs). Anyway let’s take a look at the unit test that verifies only a few of the rules and the logs that are produced from running those rules: ProductServiceImplTest.java package pl.grzejszczak.marcin.drools.decisiontable.service.drools;import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import pl.grzejszczak.marcin.drools.decisiontable.model.*; import pl.grzejszczak.marcin.drools.decisiontable.service.ProductService;import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue;/** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 03.02.13 * Time: 16:06 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class ProductServiceImplTest {private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImplTest.class);@Autowired ProductService objectUnderTest;@Test public void testRunProductLogicUserPlUnderageElectronicCountryPL() throws Exception { int initialPrice = 1000; int userAge = 6; int quantity = 10;User user = createUser("Smith", CountryType.PL, userAge); Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice); assertEquals(DecisionType.REJECTED, user.getDecision()); }@Test public void testRunProductLogicUserPlHighAgeElectronicCountryPLLowQuantity() throws Exception { int initialPrice = 1000; int userAge = 19; int quantity = 1;User user = createUser("Smith", CountryType.PL, userAge); Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice); assertEquals(DecisionType.ACCEPTED, user.getDecision()); }@Test public void testRunProductLogicUserPlHighAgeElectronicCountryPLHighQuantity() throws Exception { int initialPrice = 1000; int userAge = 19; int quantity = 8;User user = createUser("Smith", CountryType.PL, userAge); Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product); double expectedDiscount = 0.1;assertTrue(product.getPrice() == initialPrice * (1 - expectedDiscount)); assertEquals(DecisionType.ACCEPTED, user.getDecision()); }@Test public void testRunProductLogicUserUsaLowAgeElectronicCountryPLHighQuantity() throws Exception { int initialPrice = 1000; int userAge = 19; int quantity = 8;User user = createUser("Smith", CountryType.USA, userAge); Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice); assertEquals(DecisionType.REJECTED, user.getDecision()); }@Test public void testRunProductLogicUserUsaHighAgeMedicalCountrySWELowQuantity() throws Exception { int initialPrice = 1000; int userAge = 22; int quantity = 4;User user = createUser("Smith", CountryType.USA, userAge); Product product = createProduct("Some name", initialPrice, CountryType.SWE, ProductType.MEDICAL, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice); assertEquals(DecisionType.ACCEPTED, user.getDecision()); }@Test public void testRunProductLogicUserUsaHighAgeMedicalCountrySWEHighQuantity() throws Exception { int initialPrice = 1000; int userAge = 22; int quantity = 8;User user = createUser("Smith", CountryType.USA, userAge); Product product = createProduct("Some name", initialPrice, CountryType.SWE, ProductType.MEDICAL, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product); double expectedDiscount = 0.25;assertTrue(product.getPrice() == initialPrice * (1 - expectedDiscount)); assertEquals(DecisionType.ACCEPTED, user.getDecision()); }private void printInputs(User user, Product product) { LOGGER.debug(ReflectionToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); LOGGER.debug(ReflectionToStringBuilder.reflectionToString(product, ToStringStyle.MULTI_LINE_STYLE)); }private User createUser(String name, CountryType countryType, int userAge){ User user = new User(); user.setUserName(name); user.setUserCountry(countryType); user.setUserAge(userAge); return user; }private Product createProduct(String name, double price, CountryType countryOfOrigin, ProductType productType, int quantity){ Product product = new Product(); product.setPrice(price); product.setCountryOfOrigin(countryOfOrigin); product.setName(name); product.setType(productType); product.setQuantity(quantity); return product; }} Of course the log.debugs in the tests are totally redundant but I wanted you to quickly see that the rules are operational. Sorry for the length of the logs but I wrote a few tests to show different combinations of rules (in fact it’s better too have too many logs than the other way round  ) pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1d48043[ userName=Smith userAge=6 userCountry=PL decision=<null> decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1e8f2a0[ name=Electronic type=ELECTRONIC price=1000.0 countryOfOrigin=PL additionalInfo=<null> quantity=10 ] pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, according to your age (< 18) and country (PL) you can't buy this product pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:29 Sorry, user has been rejected... pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1d48043[ userName=Smith userAge=6 userCountry=PL decision=REJECTED decisionDescription=Sorry, according to your age (< 18) and country (PL) you can't buy this product ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1e8f2a0[ name=Electronic type=ELECTRONIC price=1000.0 countryOfOrigin=PL additionalInfo=<null> quantity=10 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@b28f30[ userName=Smith userAge=19 userCountry=PL decision=<null> decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@d6a0e0[ name=Electronic type=ELECTRONIC price=1000.0 countryOfOrigin=PL additionalInfo=<null> quantity=1 ] pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, no discount will be granted. pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order... pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@b28f30[ userName=Smith userAge=19 userCountry=PL decision=ACCEPTED decisionDescription=Congratulations, you have successfully bought the product ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@d6a0e0[ name=Electronic type=ELECTRONIC price=1000.0 countryOfOrigin=PL additionalInfo=Sorry, no discount will be granted. quantity=1 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@14510ac[ userName=Smith userAge=19 userCountry=PL decision=<null> decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1499616[ name=Electronic type=ELECTRONIC price=1000.0 countryOfOrigin=PL additionalInfo=<null> quantity=8 ] pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations - you've been granted a 10% discount! pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order... pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@14510ac[ userName=Smith userAge=19 userCountry=PL decision=ACCEPTED decisionDescription=Congratulations, you have successfully bought the product ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1499616[ name=Electronic type=ELECTRONIC price=900.0 countryOfOrigin=PL additionalInfo=Congratulations - you've been granted a 10% discount! quantity=8 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@17667bd[ userName=Smith userAge=19 userCountry=USA decision=<null> decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@ad9f5d[ name=Electronic type=ELECTRONIC price=1000.0 countryOfOrigin=PL additionalInfo=<null> quantity=8 ] pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, according to your age (< 18) and country (USA) you can't buy this product pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:29 Sorry, user has been rejected... pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@17667bd[ userName=Smith userAge=19 userCountry=USA decision=REJECTED decisionDescription=Sorry, according to your age (< 18) and country (USA) you can't buy this product ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@ad9f5d[ name=Electronic type=ELECTRONIC price=1000.0 countryOfOrigin=PL additionalInfo=<null> quantity=8 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@9ff588[ userName=Smith userAge=22 userCountry=USA decision=<null> decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1b0d2d0[ name=Some name type=MEDICAL price=1000.0 countryOfOrigin=SWE additionalInfo=<null> quantity=4 ] pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order... pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@9ff588[ userName=Smith userAge=22 userCountry=USA decision=ACCEPTED decisionDescription=Congratulations, you have successfully bought the product ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1b0d2d0[ name=Some name type=MEDICAL price=1000.0 countryOfOrigin=SWE additionalInfo=<null> quantity=4 ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1b27882[ userName=Smith userAge=22 userCountry=USA decision=<null> decisionDescription=<null> ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@5b84b[ name=Some name type=MEDICAL price=1000.0 countryOfOrigin=SWE additionalInfo=<null> quantity=8 ] pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you are granted a discount pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order... pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1b27882[ userName=Smith userAge=22 userCountry=USA decision=ACCEPTED decisionDescription=Congratulations, you have successfully bought the product ] pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@5b84b[ name=Some name type=MEDICAL price=750.0 countryOfOrigin=SWE additionalInfo=Congratulations, you are granted a discount quantity=8 ] In this post I’ve presented how you can push some of your developing work to your BA by giving him a tool which he can be able to work woth – the Decision Tables in a spreadsheet. What is more now you will now how to integrate Drools with Camel. Hopefully you will see how you can simplify (thus minimize the cost of implementing and supporting) the implementation of business rules bearing in mind how prone to changes they are. I hope that this example will even better illustrate how difficult it would be to implement all the business rules in Java than in the previous post about Drools. If you have any experience with Drools in terms of decision tables, integration with Spring and Camel please feel free to leave a comment – let’s have a discussion on that. All the code is available at Too Much Coding repository at Bitbucket and GitHub.   Reference: Drools decision tables with Camel and Spring from our JCG partner Marcin Grzejszczak at the Blog for coding addicts blog. ...
java-interview-questions-answers

Let us write a document style Web Service

You might be aware that there are mainly four different styles of web services we can make use of. They are as follows:Document/Literal Document/Literal Wrapped RPC/Encoded RPC/LiteralOf course the RPC/Encoded style is now deprecated. If you are interested you can read up on the different styles of web services and their pros on cons on this very comprehensive article found here. Today we will see how to write a Document/Literal wrapper kind of a web service. The agenda of this post is as follows:Write a simple web service based on Document/Literal wrapped How to host the simple web service on a tomcat web container A simple test client to test our serviceSo let us begin our journey:Write a simple web service based on Document/Literal wrappedpackage com.wsbindings;import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.ParameterStyle; import javax.jws.soap.SOAPBinding.Style; import javax.jws.soap.SOAPBinding.Use;@WebService @SOAPBinding(style = Style.DOCUMENT, use = Use.LITERAL, parameterStyle = ParameterStyle.WRAPPED) public interface AddService {@WebMethod public int addIntegers(@WebParam(name = "intOne") int paramOne, @WebParam(name = "intTwo") int paramTwo); } So this is our basic web service. This is our base interface for our service. As you can see, we first annotate it with the @javax.jws.WebService to indicate that its a web service we are going to write. Then comes the interesting part where we define our SOAPBinding. Here we state that we want to write a DOCUMENT style web service which is LITERAL and is a WRAPPED style. One thing to note here is that all three attribute values specified within the Soap Binding annotation are the default values so you can get away without declaring them here explicitly. I have done so for the purpose of clarity of this article. Moving on, let us see how the implementation will look like for this particular interface: package com.wsbindings;import javax.jws.WebService;@WebService(endpointInterface="com.wsbindings.AddService") public class AddServiceImpl implements AddService{public int addIntegers(int paramOne, int paramTwo) { return paramOne+paramTwo; }} Again nothing spectacular here in terms of what this service does. Just adds the two numbers passed in and send back the result of the addition. Note that here again we have to annotate the implementation class with the @WebService annotation. Now that we have completed the initial part of writing our web service contract and the implementation, let us see how we can host this on a tomcat web container.How to host the simple web service on a tomcat web containerAs you know, by default tomcat does not come with a JAX-WS implementation unlike typical application servers such as JBoss, Glassfish. Hence to get it working you need to get an implementation of the JAX-WS specification. In this instance we will be using Metro. You can either copy the jar files from the download to your WEB-INF/lib directory or you can make use of Maven to do that for you, which is what i will be doing in this article. So to get the require jar files related to the Metro implementation i add the following dependency to my pom: <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>2.1.3</version> <exclusions> <exclusion> <groupId>com.sun.xml.stream</groupId> <artifactId>sjsxp</artifactId></exclusion> </exclusions> </dependency> Note that i have added one exclusion here for the sjsxp artifact since i needed a newer version than which was being drawn up from transitive dependency. Because else you will get the following exception.  Could not initialize class javax.xml.stream.XMLStreamException: Underlying stream encoding UTF-8 and input paramter for writeStartDocument() method utf-8 do not match. In order to overcome this issue i needed to add the following dependency to my pom: <dependency> <groupId>com.sun.xml.stream</groupId> <artifactId>sjsxp</artifactId> <version>1.0.1</version> </dependency> I was able to find this solution thanks to this thread. Moving on, we need to define a specific xml file which should go under the WEB-INF directory called sun-jaxws.xml. This XML specifies how we can access our web services and where the implmentation class is found. Lets look at the content of this file: <?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="AddWS" implementation="com.wsbindings.AddServiceImpl" url-pattern="/addws"/> </endpoints> Here we give the package in which our web service implementation class resides in as well as the URL pattern on how to access the particular web service. One last thing we should do is to add the following to our web.xml in order to host our web service successfully: <listener> <listener-class> com.sun.xml.ws.transport.http.servlet.WSServletContextListener </listener-class> </listener> <servlet> <servlet-name>AddWS</servlet-name> <servlet-class> com.sun.xml.ws.transport.http.servlet.WSServlet </servlet-class> </servlet><servlet-mapping> <servlet-name>AddWS</servlet-name> <url-pattern>/addws</url-pattern> </servlet-mapping> Note that we have to define a context listener and a Servlet class which will handle our web service invocations. If you look at the source of the WSServletContextListner you will see it reads the sun-jaxws.xml file from the WEB-INF directory and creates class loaders accordingly for the web service context. One thing about Document style web services is that you need to generate some code for the request and response. If you do not do this, you will get the following error with the following message: Have you run APT to generate them? You can generate the required classes using the wsgen tool which comes bundled up with your JDK installation. You can also use Apache-CXF to generate these classes for you. We will use the latter approach by using the apache-cxf maven plugin which is available for us. Include the following to your pom and your good to go; <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>2.0.9</version> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>2.0.9</version> </dependency> </dependencies> <executions> <execution> <id>generate-wsdl</id> <phase>process-classes</phase> <configuration> <className>com.wsbindings.AddServiceImpl</className> <argline>-classdir ${project.build.directory}/classes</argline></configuration><goals> <goal>java2wsdl</goal> </goals> </execution> </executions> </plugin> Here we are using the java2wsdl command to generate the required request and response objects for our web service. As you can see i have used the <argline> attribute to specify where i want my generated classes to go to. Since the normal maven compile task which is run when building the war file will look in the classes directory, i have specified our classes to be included in the same path as well so that they will be bundled along with our web service class when the war is created. You can see all possible commands you can issue by going through the parameters specified here. My pom was indicating an error when i included my apache-cxf maven plugin as follows: Plugin execution not covered by lifecycle configuration and after some research on the problem i stumbled upon a solution as stated here.Hence to overcome this issue you have to include the following snippet under the <build> tag of your pom: <pluginManagement> <plugins> <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. --> <plugin> <groupId>org.eclipse.m2e</groupId> <artifactId>lifecycle-mapping</artifactId> <version>1.0.0</version> <configuration> <lifecycleMappingMetadata> <pluginExecutions> <pluginExecution> <pluginExecutionFilter> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>2.0.9</version> <goals> <goal>test-compile</goal> <goal>compile</goal> </goals> </pluginExecutionFilter> <action> <execute /> </action> </pluginExecution> </pluginExecutions> </lifecycleMappingMetadata> </configuration> </plugin> </plugins> </pluginManagement> That should get rid of that error for you though i cannot give you an exact reason to why that warning pops up. If any of you know the exact reason, i would appreciate if you could leave a comment for the benefit of us all. After that you can simply generate the war file and copy it to the webapps directory of tomcat. Then you will be able to access the web service on the following path: http://localhost:8080/ws-bindings/addws Where 8080 is the port on which i have hosted tomcat on and ws-bindings is the name of my war file. Lastly let us see how to generate the client stubs required for our service and then write a small client to test our web service.A simple test client to test our serviceWe will yet again use the apache-cxf maven plugin to generate the client stubs using the wsdl2java command. Note that first we need to get the wsdl from the path where our web service is hosted. It will be located at; http://localhost:8080/ws-bindings/addws?wsdl Then i copied the content to a separate xml file and saved it under a resources directory on the separate maven project i created to generate the client stubs. Then all you need to do is add the configuration required to generate the stubs in the pom as follows; <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>2.0.9</version> <executions> <execution> <id>generate-sources</id> <phase>generate-sources</phase> <configuration><wsdlOptions> <wsdlOption> <wsdl>${project.basedir}/src/main/resources/AddService.wsdl</wsdl> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin> This will generate the required stubs for you to test your web service. Lastly let us write a client to use the generated stub to access our web service; import java.net.MalformedURLException; import java.net.URL;import javax.xml.namespace.QName; import javax.xml.ws.Service;import com.wsbindings.AddService;public class DocWrapperClient {public static void main(String[] args) throws MalformedURLException { URL wsdlLocation = new URL("http://localhost:8080/ws-bindings/addws?wsdl");QName qName = new QName("http://wsbindings.com/", "AddServiceImplService");Service service = null; service = Service.create(wsdlLocation, qName);AddService ser = service.getPort(AddService.class); System.out.println(ser.addIntegers(1, 1)); } } That is about it guys, and i hope you found the content useful. You can check out the example by downloading the server related maven project from here and the client stub generation maven project from here.   Reference: Let us write a document style Web Service from our JCG partner Dinuka Arseculeratne at the My Journey Through IT blog. ...
agile-logo

Agile Product Planning: Vision, Strategy, and Tactics

Product planning is just as important in an agile context as it is in a traditional setting. Unfortunately, some product owners focus so much on the product details and the tactical level that other planning aspects are neglected. But writing the right user stories and creating the right user interface design is difficult, if we haven’t thought about the product strategy; and choosing the right strategy is hard if we don’t have a vision of what we want to achieve. The Planning Levels Agile product planning comprises three levels: vision, product strategy, and tactics. The vision is the overarching goal, the product strategy the path to the vision, and the   tactics are the steps along the way, as the following diagram illustrates:The level of detail increases, as we move down from the vision to the tactics: Whereas the vision is typically captured by a brief statement, the strategy communicates different aspects including the market or market segment targeted, the product price and the channels, and the product’s unique selling points (USP’s). The tactics go further by describing the product details employing, for instance, user stories, design sketches, scenarios, and storyboards, as the following picture shows:The Vision Product planning starts with creating a vision: an overarching, shared goal that guides people. A sample vision from my own company is: “Grow Pichler Consulting without increasing headcount.” This vision may not sound mega exciting but it is very helpful for my team and me: It guides our work and focuses our efforts. Note that the sample vision doesn’t mention a specific product or service. It rather states a business goal. How the goal is realised is captured in the product strategy. The Product Strategy The product strategy is the path chosen to realise the vision. Without a strategy, making the right decisions about the product details is difficult: the functionality, the design, and the non-functional properties the product should exhibit. Having a strategy in place also prevents me from getting lost in the details. I find it helpful to capture the target group, the needs addressed, the key features of the product, and the desired business benefits in the product strategy. But you may want to add the product price, the channels, the main competitors, and other important business model elements to characterise your strategy more comprehensively. As the strategy is a path to the vision, it may turn out to be wrong. This is particularly likely when a new product is created. Changing the strategy is also called a pivot. My strategy for growing Pichler Consulting, for instance, is to develop an e-learning course. If I discover that the course is unlikely to be successful, I may change the strategy and write a new book instead. While the strategy may turn out to be wrong, the vision should still be valid. The Product Tactics The product tactics describe the product details: the product functionality, the user interaction, and the user interface design. Great techniques to capture these aspects are epics and ready stories, scenarios, design sketches and mock-ups, constraint stories, and sprint goals. New product features are best delivered incrementally so we can learn from the feedback we collect. I use blog posts, for instance, to create the material for my e-learning course. This allows me to learn from the feedback I receive, and to validate my strategy and the product details. Product Planning Tools I prefer to use the agile product planning tools shown in the picture below:For new or innovative products, I employ the Product Vision Board and the Business Model Canvas. The former helps me capture my vision and the key elements of the product strategy; the latter helps me describe additional aspects including price and channels. To capture the details, I use the Product Canvas. The canvas allows me to work with personas, epics, scenarios and storyboards, design sketches and mock-ups, constraint stories, sprint goals, and ready stories. For incremental product updates, I like to employ a goal-oriented or theme-based product roadmap in order to capture the product strategy. I normally use a traditional product backlog to describe the product details. Summary Creating successful products requires more than attention to the product details. Ensure you have a shared in vision in place, and choose a strategy that guides you towards the vision. Use early feedback to validate if you are on the right path, if your strategy is valid. Let the product strategy help you decide what your product should look like and do.   Reference: Agile Product Planning: Vision, Strategy, and Tactics from our JCG partner Roman Pichler at the Pichler’s blog blog. ...
java-logo

JDK 8 Javadoc Tweaked For Methods Listings

Since it’s beginning, Javadoc output has been largely static HTML with navigation links and simple stylesheet styling of its appearance. Java SE 7 saw the first significant change in Javadoc output default appearance in a long time and now it looks like JDK 8 will introduce a new twist on generated Javadoc output. In this post, I look briefly at the more dynamic filtering of methods in Javadoc output by type of method that appears to be available with JDK 8’s javadoc tool. The following two screen snapshots compare the JDK 7 and JDK 8 versions of default Javadoc output for the Calendar class (chosen for its variety of method types).Although the Javadoc output for JDK 8 has the same overall styles (including orange “tabs” for “Constructors”, “Fields”, “Methods” and so forth) as Java 7 Javadoc documentation, the methods in the JDK 8 generated documentation have multiple orange tabs above the listing of methods that allow the reader to click on the appropriate tab to see the appropriate subset of methods. The names of the tabs are about as self-explanatory as you could want with names like “All Methods” (all methods on the class), “Static Methods” (class-level methods), “Instance Methods” (object-level methods), “Abstract Methods” (methods without implementation), and “Concrete Methods” (implemented methods). The next series of screen snapshots demonstrate how clicking on any of these tabs invokes embedded JavaScript code that calls appropriate functions in the script.js file that exists at the root level of the generated Javadoc directory structure.This is a minor, but still somewhat handy, feature of Javadoc in JDK 8. I have often looked through methods of Javadoc for a class with mixed method types for methods that fit one particular type. Now, rather than needing to scan for keywords such as “static” or “abstract” or for the absence of those same words, I can simply use these “tabs” to filter the types of methods I want to see for a given class. Reference: JDK 8 Javadoc Tweaked For Methods Listings from our JCG partner Dustin Marx at the Inspired by Actual Events blog. ...
java-logo

Arrays.sort versus Arrays.parallelSort

We all have used Arrays.sort to sort objects and primitive arrays. This API used merge sort OR Tim Sort underneath to sort the contents as shown below:                   public static void sort(Object[] a) { if (LegacyMergeSort.userRequested) legacyMergeSort(a); else ComparableTimSort.sort(a); } This is all done sequentially, even though merge sort uses divide and conquer technique, its all done sequentially. Come Java 8, there is a new API introduced for sorting which is Arrays#parallelSort. This is does the sorting in parallel. Interesting right! Lets see how it does… Arrays#parallelSort uses Fork/Join framework introduced in Java 7 to assign the sorting tasks to multiple threads available in the thread pool. This is called eating your own dog food. Fork/Join implements a work stealing algorithm where in a idle thread can steal tasks queued up in another thread. An overview of Arrays#parallelSort: The method uses a threshold value and any array of size lesser than the threshold value is sorted using the Arrays#sort() API (i.e sequential sorting). And the threshold is calculated considering the parallelism of the machine, size of the array and is calculated as: private static final int getSplitThreshold(int n) { int p = ForkJoinPool.getCommonPoolParallelism(); int t = (p > 1) ? (1 + n / (p << 3)) : n; return t < MIN_ARRAY_SORT_GRAN ? MIN_ARRAY_SORT_GRAN : t; } Once its decided whether to sort the array in parallel or in serial, its now to decide how to divide the array in to multiple parts and then assign each part to a Fork/Join task which will take care of sorting it and then another Fork/Join task which will take care of merging the sorted arrays. The implementation in JDK 8 uses this approach: – Divide the array into 4 parts. – Sort the first two parts and then merge them. – Sort the next two parts and then merge them. And the above steps are repeated recursively with each part until the size of the part to sort is not lesser than the threshold value calculated above. Some interesting results: I tried to compare the time taken by the Arrays#sort and Arrays#parallelSort on a machine with 4 CPUs. The program which I used for this comparison is: public class ArraysParallelDemo { public static void main(String[] args) throws FileNotFoundException { List<Double> arraySource = new ArrayList<>();Scanner reader = new Scanner(ClassLoader. getSystemResourceAsStream("java8demo/large_array_input")); while(reader.hasNext()){ String line = reader.nextLine(); String[] strNums = line.split(","); for ( String strN : strNums){ arraySource.add(Double.parseDouble(strN)); } }System.out.println(arraySource.size());Double [] myArray = new Double[1]; myArray = arraySource.toArray(myArray); long startTime = System.currentTimeMillis(); Arrays.sort(myArray); long endTime = System.currentTimeMillis(); System.out.println("Time take in serial: "+ (endTime-startTime)/1000.0);Double [] myArray2 = new Double[1]; myArray2 = arraySource.toArray(myArray); startTime = System.currentTimeMillis(); Arrays.parallelSort(myArray2); endTime = System.currentTimeMillis(); System.out.println("Time take in parallel: "+ (endTime-startTime)/1000.0);} } And the time taken by each of the APIs against arrays of double values of different sizes is shown below:There is a similar implementation for Lists as well and lot of the operations on Lists have a parallel equivalent.   Reference: Arrays.sort versus Arrays.parallelSort from our JCG partner Mohamed Sanaulla at the Experiences Unlimited blog. ...
grails-logo

Groovy & Grails Understanding – Part 1

Introduction Enterprises today require agile platform for rapid development of applications with ready assurance to quality of services, compliance to architecture and design standards. Two key things influence our ability to be agile. First, it’s the attitude of everyone involved. Second it’s the languages, framework, and tools we use to get our work done. There are languages and frameworks such as Groovy and Grails, emerge in recent years that support a more agile development approach. Groovy, is a dynamic language that works on top of the Java Virtual Machine. Groovy, developed in 2003 by James Strachan and Bob McWhirter [ 28 ], is a language that is very similar to languages like Ruby, Smalltalk, Python and Perl. Grails is an open-source web application framework on top of the Groovy which exercise convention – over – configuration, honor the DRY (Don’t Repeat Yourself) principle, and is overall lightweight- making it a sound agile framework. Groovy Groovy is an object-oriented programming language for the Java platform. It is a dynamic language with features similar to those of Python, Ruby, Perl, and Smalltalk. It can be used as a scripting language for the Java Platform. It is dynamically compiled to Java Virtual Machine (JVM) byte code and interoperates with other Java code and libraries. Groovy…is an agile and dynamic language for the Java Virtual Machine builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk makes modern programming features available to Java developers with almost-zero learning curve supports Domain-Specific Languages and other compact syntax so your code becomes easy to read and maintain makes writing shell and build scripts easy with its powerful processing primitives, OO abilities and an Ant DSL increases developer productivity by reducing scaffolding code when developing web, GUI, database or console applications simplifies testing by supporting unit testing and mocking out-of-the-box seamlessly integrates with all existing Java classes and libraries compiles straight to Java byte code so you can use it anywhere you can use JavaArchitecture Groovy uses a Java-like syntax which is dynamically compiled to Java byte code therefore Groovy can seamlessly work together with Java code and Java libraries. Groovy with Java make Groovy very powerful. When an application needs functionality that can’t be achieved with the existing Groovy libraries, the developer can still write Java code to achieve the goal and vice versa Java code can be converted to GroovyGroovy is like a super version of Java. It can leverage Java’s enterprise capabilities but also has cool productivity features like action, builders and dynamic typing. Groovy Development Environment Groovy requires Java, so you need to have a version available (while groovy 1.6 supports JDK 1.4 or greater, for groovy 1.7 onwards, minimum JDK 1.5 is needed). Download the Groovy installer or binaries from the downloads page (http://groovy.codehaus.org/Download) and follow the installation instruction Download binarySet GROOVY_HOME Add GROOVY_HOME/bin to your PATH Set JAVA_HOMESemicolons The use of semicolons ( ; ) in Groovy is completely optional . The only time a semicolon has to be used, is when multiple function calls are placed on the same lineData type declaration When creating an object, it’s type doesn’t have to be defined explicitly. By using the def-keyword, Groovy will automatically detect what object type has to be usedAlthough optional, Groovy still enables object types to be declared explicitly. This might be useful in situations where only one data type is allowed. Groovy String The Groovy String (Also called “GString”) allows for any type of logic to be integrated in the String definition. This can be done with the dollar symbol ( $ ) and (optional) braces ( { } ). The difference between a String and a GString is automatically recognized by Groovy.Embedded quotes Groovy has a nice way of working with Strings. In Java, a single quote would represent the primitive type char. In Groovy, anything that is surrounded by either single or double quotes is converted to a String. This is very useful when working with Strings that contain quotes. As this example will show, Strings with doubles quotes in it can be surrounded with single quotes en vice versa. To escape a quote, a backslash is usedCollections Groovy acknowledges three different types of collections. The first two, Lists and Maps, are no different from the ones used in Java. Lists use a null-based index to retrieve items, whereas Maps use a unique key to find an item. Ranges however, are more or less unique to dynamic languages. A simple example of a list in Groovy is:The first entry being zero in Roman, which is the word ‘nulla’ and doesn’t have a notation. A map is created by assigning values to a corresponding key, like such:Although ranges don’t appear in the standard Java libraries, most programmers have an intuitive idea of what a range is. Effectively, a range defines a start and an end point, with a notion of how to move from the start to the end point. Groovy provides literals to support for ranges, along with other language features such as the for statement, which understands ranges. Declaring a range is easy:Declaring Classes Classes are the cornerstone of object-oriented programming, because they define the blueprint from which objects are drawn. The code below contains a simple Groovy class named Book, which has an instance variable title, a constructor that sets the title, and a getter method for the title. By default, all methods are public and therefore access modifiers are excluded.Return Statements The last line of a method in Groovy is automatically the return statement. For this reason, an explicit return statement can be left outTo return a value that is not on the last line, the return statement has to be declared explicitly.Boolean Every object in Groovy has a Boolean representation, which value depends on it’s content and type. A String for instance, will return true if populated and false if empty. This allows for quick “truth”-checking, and reduces the amount of code involved.Operator overloading Operator overloading allows the default use of operators to be overridden to enable a more intuitive approach for common methods. The way Groovy implements this, can be seen in the following table.Loops Because of Groovy’s origin in Java, it natively supports both the for- and while-loop. Groovy’s for-each loops though, have a slight difference in syntax when compared with their Java equivalents. A Java for-each loop looks like this:Groovy’s counterpart however, uses the keyword ‘in’ instead of Java’s colonGroovy has some special capabilities for collections, among which the range. Groovy provides some extra looping techniques that can be used in collaboration with these. The each-method can be used on collections, and executes a given closure for each of the items in the list.The eachWithIndex does essentially the same, but keeps an numbered index that can be accessed from within the closure.Exception handling Groovy lets the programmer decide to catch the exception or not. In the following example, the developer tries to open and read the contents of a file. He does not need to surround the method with a try and catch block, when he knows that the file exists. Groovy gives the programmer control over the exceptions, so he chooses to throw one but he does not need to. Java would not compile the code because it expects a try and catch block that throws the exception FileNotFoundExceptionThe example above shows two ways of opening a fle: With and without a try and catch block. When the developers know that a file exists – As shown in the first example above – he doesn’t need to surround it with a try and catch. Like stated earlier, the developer can choose whether he wants to catch the exception or not – This happens in the second example above. Sometimes, code needs to catch more than one exception. Groovy allows the developer to catch all exceptions in one catch, instead of writing a catch statement for each tryNote that the code above only throws one exception: The function openFile does not exist so it directly throws an exception. If it existed, another exception would be thrown since the URL is formatted wrong. The catch would show the exception: This is the same catch as the one from open File Testing Testing in Groovy is, like testing in Java, very extensive. A common way to test a application is with JUnit testing. The name for JUnit in Groovy is GUnit. Codehaus and IBM have written articles about unit testing in Groovy. Documentation on their findings can be found on the following websites:Codehaus’s testing guide: http://groovy.codehaus.org/Testing+Guide IBM’s fndings: http://www.ibm.com/developerworks/java/library/j-pg11094/Because the subject GUnit doesn’t support our main question, this will not be fully described. Basically, it is the same as JUnit testing. Database Integration Groovy provides the user with a wrapper around the standard Java classes, adding more functionality and ease of use when working with databases. It is important to understand that Groovy currently doesn’t replace all of Java’s original databases connectivity, as the JDBC is still in use. Resourceshttp://groovy.codehaus.org/- Groovy http://en.wikipedia.org/wiki/Groovy_%28programming_language%29 – Groovy http://grails.org/ – Grails http://en.wikipedia.org/wiki/Grails_(framework) http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=mastering+grails Codehaus’s testing guide: http://groovy.codehaus.org/Testing+Guide http://www.ibm.com/developerworks/java/library/j-pg11094/  Reference: Groovy & Grails Understanding – Part 1 from our JCG partner Nitin Kumar at the Tech My Talk blog. ...
ceylon_logo

Null and Java interop

The way Ceylon handles null is one of the big attractions of the language. Ceylon features a typed null value. The object null is just an instance of the perfectly ordinary class Null from the point of view of the type system. But when the compiler backend transforms Ceylon code to Java bytecode or JavaScript, the class Null is eliminated and the value null is represented as a native Java or JavaScript null at the virtual machine level. This is great for interoperation with native Java or JavaScript. However, when designing our Java interop, we had to take into account that Java’s null isn’t typed, and that the information about whether a Java method might return null, or whether a parameter of a Java method accepts null is “missing” and not available to the   Ceylon typechecker. I think we’ve done the right thing here, but the approach we took has surprised a couple of people, so I guess it’s well worth calling explicit attention to what we’ve done and why. Consider the following useful method of java.lang.String: public String toUpperCase(Locale locale) { ... } By checking the implementation of this method, I determined that:toUpperCase() never returns null, and that the argument to locale must not be null.Unfortunately, this information isn’t available to the Ceylon typechecker. So perhaps you might expect that Ceylon would take a very heavyhanded route, treating the return type of toUpperCase() as String?, and forcing me to explicitly narrow to String using an assertion: assert (exists uppercased = javaString.toUpperCase(locale)); In fact, this is not what Ceylon does. This approach would make interoperation with Java a nightmare, resulting in code full of hundreds of useless assertions. You would need an assertion essentially every time you call a native method. Worse, the “heavyhanded” approach would prevent me from passing the value null as an argument to a parameter of a Java method. What would it mean to “assert” that a method parameter accepts null? That’s not an assertion that can be tested at runtime! Nor would the “heavyhanded” approach in practice even protect me from NullPointerExceptions. As soon as I call native Java code, a NullPointerException can occur inside the Java code I call, and there’s nothing Ceylon can do to protect me from that. So instead, Ceylon takes a “lighthanded” approach at the boundary between Java and Ceylon, letting you write this: String uppercased = javaString.toUpperCase(locale); The typechecker knows this is a Java method, and that the information about null is missing, so it assumes that you know what you’re doing and that toUpperCase() never returns null. But what if you’ve got it wrong, and toUpperCase() does return null at runtime? We would not want that null value to propagate into Ceylon values declared to contain a not-null type! What the Ceylon compiler does is insert a null check on the return value of toUpperCase(), and throws a NullPointerException to indicate the problem. If you ever see that NullPointerException, at runtime, you’re supposed to change your code to this: String? uppercased = javaString.toUpperCase(locale); This is essentially the best Ceylon can do given the information available to it. The NPE is not a bug! It’s not even really a “gotcha”. Still, the NullPointerException might look like a bug to novice user. (Indeed, Stef recently noticed someone describe it as a bug in a conference presentation.) So I’m asking myself how we can make this less surprising. There’s a range of options, including:add a better error message to the NullPointerException, throw an AssertionException instead of a NullPointerException, or even, perhaps, following the approach we use for JavaScript interop, require you to surround “lighthanded” code in a special construct that suppresses the “heavyhanded” typechecks, dynamic Null { ... } or something.I lean towards the first of these options, I suppose. Whatever we do, we need to document this better. Right now, the documentation is kinda hidden.   Reference: Null and Java interop from our JCG partner Gavin King at the Ceylon Team blog blog. ...
ceylon_logo

About modules

Modules, ah, modules. The albatross of Java. I frequently joke that modules are scheduled for Java N+1 where N moves forward with each release. I remember perfectly the first time I heard of Java getting modules at Devoxx, back when they were still planned for Java 7. I remember I heard the announcement and what I saw made a lot of sense, I couldn’t wait to get them. I agreed completely, and still do, with the assertion that modules belong in the language, just like packages, and that they should not be delegated to third-party external systems which will never be able to have the level of integration that you can achieve by being an integral part of the language. And then, they pushed it to Java 8. And then to Java 9. It’s a shame because it looks like a really well thought-out module system.     Meanwhile, Ceylon already supports modules, in a generally awesome way. But why do we need modules? Here are some easy answers:To serve as a larger container than packages. Everyone ships Java code into jars which are generally accepted to be modules: they represent a group of packages that implement a library or program and have a version. To express and resolve dependencies: your module (jar) is going to depend on other modules (jars), so we should know which they are and how to find them. To distribute modules: Linux distributions have been doing this forever. With a modular system where modules have names and versions, you can organise them in a standard hierarchy, which can then be used by tools to obtain those modules in a standard way. With dependencies, the tools can then download/upload the dependencies too, which means distribution becomes a lot simpler. To isolate modules at runtime. This is part of escaping the infamous classpath hell: if you isolate your modules at runtime, then you can have multiple programs that depend on different versions of the same module loaded at the same time.So why is it better if we have modules in the language, rather than outside of it?It’s standard and tools have to support it. You could view this as a downside, but really, what part of the Java language would you rather have left unspecified? Would you be ready to delegage the implementation of packages to third-party tools? Having a single way to deal with modules helps a lot, both users and implementors. You get rid of external tools, because suddenly javac, java and friends know how to publish, fetch and execute modules and their dependencies. No more plumbing and sub-par fittings. It gets integrated with reflection. Modules are visible at runtime, fully reified and hopefully dynamic too, just like classes and packages are. Dependencies and modules are separated from the build system. There’s absolutely no good reason why the two should be confused with one another.These are the reasons why I can’t wait for Java N+1 to have modules, I think they’ll be great. But if you need modules now, then you can use Ceylon. Ceylon support modules in the language, from the start, with:a super small ceylon.language base module, which is all you need to start using Ceylon a modular SDK a great module repository: Herd support for module repositories in all the tools, be it the command-line or the IDE. They know how to deal with dependencies, fetch or publish modules to/from local or remote repositories superb support for Herd repositories from the IDE, with the ability to search for modules, have auto-completion and all support for a modular JDK, using the same module map as the Jigsaw project (Java’s planned modular SDK) and even interoperability with Maven repositories, so that you can use Maven modules as if they were Ceylon modulesOther existing third-party module systems As I mentioned, we support using Maven repositories from Ceylon, and we will probably support OSGi too, in time. Those are the two main third-party module systems for Java. OSGi is used a lot in application servers or IDEs, but rarely by most Java programmers, which prefer Maven. Maven was the first system that provided both modularity and a build system for the JVM. Prior to that we had Ant, which only provided the build system. Maven essentially prevailed over Ant because it supported modularity, which meant that people no longer had to worry about how to get their dependencies. Even applying the modularity solution to itself, it became easier to distribute Maven modules than Ant modules. Maven supports modularity and dependencies, in order to resolve and download them, but once they are downloaded, the dependencies are crammed into the classpath, so as far as the Java compiler or runner are concerned, modularity has been erased. There is no support for multiple versions of the same module at runtime, or any kind of validation of dependencies. The undeclared transitive dependency problem We recently had bug reports for Ceylon where our users has trouble using Maven modules from Ceylon, due to missing dependencies. Since we do use the dependencies provided by Maven, we found that a bit weird. After checking, it appears that we’ve been hit by the modularity erasure of Maven. Here’s a simple example of something you can do with Maven modules:You write a module A, which uses module B and C, but you only declare a dependency on module B Module B depends on module C Module C does not depend on anythingIn Ceylon, if you tried to compile module A, the compiler would not let you because you failed to depend on C. With Maven, it just works, because Maven fetches modules B and C and puts them in the classpath, which means all implicit transitive dependencies end up visible to your module. Modularity is erased. This may seem convenient, but it really means that dependencies are not checked and cannot be trusted. Due to that, we can’t rely on Maven modules to properly declare their dependencies, so we cannot run Maven modules in isolation. The undeclared implicit dependency problem There’s something more subtly wrong with unchecked module systems: implicit dependencies. This is something you’re allowed to do with Maven:Module A uses module B Module B depends on module C and declares it Module B uses types from module C in it public API, such as parameter types, method or field types, or even super classesThis is a variant of the first kind of problem, except that in this case nobody can use module B without also importing module C directly, because it’s not possible to use the types of module B without seeing the types of modules C. In Ceylon, if you tried to compile module B, the compiler would not let you unless you export your module C dependency. This way, when you depend on module B, you automatically also depend on module C, because you really need both to be visible to be able to use module B’s API. Another point in favour of integrated module systems If we had an integrated module system from the start, in Java, with proper module isolation, we would not have the issues I just described with missing dependencies that are so widespread in Maven, because there are no tools to prevent you from making these mistakes. Compilers do not let you use packages unless you import them, there’s no reason to expect that the same would not hold for modules. I still think the modules project for Java will be a great leap forward, but since Java N+1 is still not here, and there’s a huge library of Maven modules that we want to be able to use, we have to find a way to bypass the limitations of Maven’s dependency declarations to let you use them in Ceylon. We have various ideas of how to do that, from automatic detection of dependencies through bytecode analysis, to storing Maven modules in a “flat classpath” container, or even via dependency overrides where users could “fix” Maven dependencies. We’re still in the process of evaluating each of these solutions, but if you have other suggestions, feel free to pitch in.   Reference: About modules from our JCG partner Stef Epardaud at the Ceylon Team blog blog. ...
json-logo

Spring MVC – Easy REST-Based JSON Services with @ResponseBody

Spring 3 makes JSON REST services really easy. This tutorial will show you how in just a few steps. You can grab the code on GitHub. Prerequisites You should have a working Spring MVC Application. If you do not already have a working Spring MVC application set up, follow this tutorial. We will define three REST services: 1) to retrieve a random Person, 2) to retrieve a Person by ID, and 3) to save a new Person. The services will be consumed using jQuery on a sample page we will set up. First, I will show the Spring Controller for our REST services, and then we will walk through how they work: PersonController.java package com.codetutr.controller;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody;import com.codetutr.domain.Person; import com.codetutr.service.PersonService;@Controller @RequestMapping("api") public class PersonController {PersonService personService;@Autowired public PersonController(PersonService personService) { this.personService = personService; }@RequestMapping("person/random") @ResponseBody public Person randomPerson() { return personService.getRandom(); }@RequestMapping("person/{id}") @ResponseBody public Person getById(@PathVariable Long id) { return personService.getById(id); }/* same as above method, but is mapped to * /api/person?id= rather than /api/person/{id} */ @RequestMapping(value="person", params="id") @ResponseBody public Person getByIdFromParam(@RequestParam Long id) { return personService.getById(id); }/** * Saves new person. Spring automatically binds the name * and age parameters in the request to the person argument * @param person * @return String indicating success or failure of save */ @RequestMapping(value="person", method=RequestMethod.POST) @ResponseBody public String savePerson(Person person) { personService.save(person); return "Saved person: " + person.toString(); } } OK, so, as you can see, we have 4 request handlers in this controller. The first method returns a random person. The next two retrieve a person by ID – just two different approaches to the URL mapping. The last method saves a person. Remember how Spring controllers usually return a type String (to indicate the resulting view name). Instead, here we are using Spring’s @ResponseBody annotation and returning the object that we want to send to the client. The @ResponseBody annotation tells Spring that we will be returning data in the response body rather than rendering a JSP. When the @ResponseBody annotation is used, Spring will return the data in a format that is acceptable to the client. That is, if the client request has a header to accept json and Jackson-Mapper is present in the classpath, then Spring will try to serialize the return value to JSON. If the request header indicates XML as acceptable (accept=application/xml) and Jaxb is in the classpath and the return type is annotated with Jaxb annotation, Spring will try to marshall the return value to XML. As I mentioned, if you want your services to return JSON, you have to have Jackson in the classpath. Here is the only dependency you need to add to your project: Gradle compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.12' Or, if you’re using Maven: <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.12</version> </dependency> Alternatively, if you want your services to return XML, include your favorite Jaxb implementation, eg. com.sun.xml.bind:jaxb:2.1.9. In a minute, we’ll build a front end to call these services using AJAX, but if you deploy your application now, you can try out your services using a REST client (or just typing the URL into your browser). Eg:You can stop following along if you’re content with that. I will just connect all the pieces now by coding the client-side jQuery: home.jsp <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %><!DOCTYPE HTML> <html> <head> <title>Spring MVC - Ajax</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <style> body { background-color: #eee; font: helvetica; } #container { width: 500px; background-color: #fff; margin: 30px auto; padding: 30px; border-radius: 5px; box-shadow: 5px; } .green { font-weight: bold; color: green; } .message { margin-bottom: 10px; } label { width:70px; display:inline-block;} .hide { display: none; } .error { color: red; font-size: 0.8em; } </style> </head> <body> <div id="container"> <h1>Person Page</h1> <p>This page demonstrates Spring MVC's powerful Ajax functionality. Retrieve a random person, retrieve a person by ID, or save a new person, all without page reload. </p> <h2>Random Person Generator</h2> <input type="submit" id="randomPerson" value="Get Random Person" /><br/><br/> <div id="personResponse"> </div> <hr/> <h2>Get By ID</h2> <form id="idForm"> <div class="error hide" id="idError">Please enter a valid ID in range 0-3</div> <label for="personId">ID (0-3): </label><input name="id" id="personId" value="0" type="number" /> <input type="submit" value="Get Person By ID" /> <br /><br/> <div id="personIdResponse"> </div> </form> <hr/> <h2>Submit new Person</h2> <form id="newPersonForm"> <label for="nameInput">Name: </label> <input type="text" name="name" id="nameInput" /> <br/> <label for="ageInput">Age: </label> <input type="text" name="age" id="ageInput" /> <br/> <input type="submit" value="Save Person" /><br/><br/> <div id="personFormResponse" class="green"> </div> </form> </div> <script type="text/javascript"> $(document).ready(function() { // Random Person AJAX Request $('#randomPerson').click(function() { $.getJSON('${pageContext.request.contextPath}/api/person/random', function(person) { $('#personResponse').text(person.name + ', age ' + person.age); }); }); // Request Person by ID AJAX $('#idForm').submit(function(e) { var personId = +$('#personId').val(); if(!validatePersonId(personId)) return false; $.get('${pageContext.request.contextPath}/api/person/' + personId, function(person) { $('#personIdResponse').text(person.name + ', age ' + person.age); }); e.preventDefault(); // prevent actual form submit }); // Save Person AJAX Form Submit $('#randomPerson').click(function() { $.getJSON('${pageContext.request.contextPath}/api/person/random', function(person) { $('#personResponse').text(person.name + ', age ' + person.age); }); }); $('#newPersonForm').submit(function(e) { // will pass the form date using the jQuery serialize function $.post('${pageContext.request.contextPath}/api/person', $(this).serialize(), function(response) { $('#personFormResponse').text(response); }); e.preventDefault(); // prevent actual form submit and page reload }); }); function validatePersonId(personId) { console.log(personId); if(personId === undefined || personId < 0 || personId > 3) { $('#idError').show(); return false; } else { $('#idError').hide(); return true; } } </script> </body> </html> Once you have everything in place, you should have a page that looks like this:Full Source:  ZIP, GitHub To run the code from this tutorial: Must have Gradle installed. Download the ZIP. Extract. Open command prompt to extracted location. Run gradle jettyRunWar. Navigate in browser to http://localhost:8080. ReferencesSpringSource Blog – Spring MVC Ajax Simplifications SpringSource Blog – Spring MVC Enhancements  Reference: Spring MVC – Easy REST-Based JSON Services with @ResponseBody from our JCG partner Steve Hanson at the CodeTutr blog. ...
java-interview-questions-answers

MOXy’s Object Graphs & Dynamic JAXB

JAXB (JSR-222) makes it easy for you to convert instances of your domain classes to/from XML.  The EclipseLink MOXy implementation offers an extension called Dynamic JAXB where instead of real classes you have instances of a map like class called DynamicEntity. You can access the data on your DynamicEntity using get and set methods that take the property name (i.e. customer.get(“address”) and customer.set(‘name”, “Jane Doe”). In this post, first we will bootstrap a dynamic JAXBContext based on an external mapping file.  Then we unmarshal an XML document to dynamic entities, and finally we will apply an object graph to scope the resulting JSON output.       You can try this out today by downloading an EclipseLink 2.5.0 nightly download starting on March 24, 2013 from:http://www.eclipse.org/eclipselink/downloads/nightly.phpDynamic Java Model With a static model the metadata is derived from the Java classes and augmented by any provided metadata (see: JAXB – No Annotations Required ).   Since in MOXy’s dynamic JAXB there are no domain classes the types must be completely defined by metadata.  This can be done from an XML schema or as done in this example using MOXy’s external mapping document. oxm.xml Since there are no real Java classes, in the external mapping document we need to specify each mapping, and for each mapping the type of the Java property. <?xml version="1.0"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="blog.objectgraphs.dynamic"> <java-types> <java-type name="Customer"> <xml-named-object-graphs> <xml-named-object-graph name="contact info"> <xml-named-attribute-node name="name"/> <xml-named-attribute-node name="billingAddress" subgraph="location"/> <xml-named-attribute-node name="phoneNumbers" subgraph="simple"/> <xml-named-subgraph name="location"> <xml-named-attribute-node name="city"/> <xml-named-attribute-node name="province"/> </xml-named-subgraph> </xml-named-object-graph> </xml-named-object-graphs> <xml-root-element/> <java-attributes> <xml-attribute java-attribute="id" type="java.lang.Integer"/> <xml-element java-attribute="name" type="java.lang.String"/> <xml-element java-attribute="billingAddress" type="blog.objectgraphs.dynamic.Address"/> <xml-element java-attribute="shippingAddress" type="blog.objectgraphs.dynamic.Address"/> <xml-element java-attribute="phoneNumbers" name="phoneNumber" type="blog.objectgraphs.dynamic.PhoneNumber" container-type="java.util.List"> <xml-element-wrapper/> </xml-element> </java-attributes> </java-type> <java-type name="Address"> <java-attributes> <xml-element java-attribute="street" type="java.lang.String"/> <xml-element java-attribute="city" type="java.lang.String"/> <xml-element java-attribute="province" type="java.lang.String"/> <xml-element java-attribute="postalCode" type="java.lang.String"/> </java-attributes> </java-type> <java-type name="PhoneNumber"> <xml-named-object-graphs> <xml-named-object-graph name="simple"> <xml-named-attribute-node name="value"/> </xml-named-object-graph> </xml-named-object-graphs> <java-attributes> <xml-attribute java-attribute="type" type="java.lang.String"/> <xml-value java-attribute="value" type="java.lang.String"/> </java-attributes> </java-type> </java-types> </xml-bindings> jaxb.properties A jaxb.properties file is used to specify the JAXB provider.  For dynamic JAXB the contents of this file are slightly different than usual when using MOXy (compare with Specifying EclipseLink MOXy as your JAXB Provider).  This file goes in the same package as the domain model, since here we have a virtual domain model the jaxb.properties file would be the only real item in the blog.objectgraphs.dynamic package. javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory Demo Code Below we will explore two different approaches for using object graphs. Demo – Object Graph Specified through Metadata In the demo code below we will leverage the object graph that was defined in the external mapping document.  The object graph was defined for the dynamic model exactly as it was for the corresponding static model (see: MOXy’s Object Graphs – Input/Ouput Partial Models to XML & JSON).  The only thing that is different is that the object we get from the unmarshal call is an instance of DynamicEntity rather than Customer. package blog.objectgraphs.dynamic;import java.io.File; import java.util.*; import javax.xml.bind.*; import org.eclipse.persistence.dynamic.DynamicEntity; import org.eclipse.persistence.jaxb.JAXBContextProperties; import org.eclipse.persistence.jaxb.MarshallerProperties;public class DemoMetadata {public static void main(String[] args) throws Exception { Map<String, Object> properties = new HashMap<String, Object>(1); properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "blog/objectgraphs/dynamic/oxm.xml"); JAXBContext jc = JAXBContext.newInstance("blog.objectgraphs.dynamic", DemoMetadata.class.getClassLoader(), properties);Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("src/blog/objectgraphs/dynamic/input.xml"); DynamicEntity customer = (DynamicEntity) unmarshaller.unmarshal(xml);// Output XML Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(customer, System.out);// Output XML - Based on Object Graph marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "contact info"); marshaller.marshal(customer, System.out);// Output JSON - Based on Object Graph marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json"); marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false); marshaller.setProperty(MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); marshaller.marshal(customer, System.out); }} Demo – Object Graph Created Programatically In the demo code below we will create object graph programmatically.  The object graph was created for the dynamic model exactly as it was for the corresponding static model (see: MOXy’s Object Gaphs – Partial Models on the Fly to/from XML & JSON).  What is different is that we used the name of the dynamic entity to create the object graph instead of the class, and we get an instance of DynamicEntity rather than Customer from the unmarshal call. package blog.objectgraphs.dynamic;import java.io.File; import java.util.*; import javax.xml.bind.*; import org.eclipse.persistence.dynamic.DynamicEntity; import org.eclipse.persistence.jaxb.JAXBContextProperties; import org.eclipse.persistence.jaxb.JAXBHelper; import org.eclipse.persistence.jaxb.MarshallerProperties; import org.eclipse.persistence.jaxb.ObjectGraph; import org.eclipse.persistence.jaxb.Subgraph;public class DemoRuntime {public static void main(String[] args) throws Exception { Map<String, Object> properties = new HashMap<String, Object>(1); properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "blog/objectgraphs/dynamic/oxm.xml"); JAXBContext jc = JAXBContext.newInstance("blog.objectgraphs.dynamic", DemoMetadata.class.getClassLoader(), properties);Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("src/blog/objectgraphs/dynamic/input.xml"); DynamicEntity customer = (DynamicEntity) unmarshaller.unmarshal(xml);// Output XML Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(customer, System.out);// Create the Object Graph ObjectGraph contactInfo = JAXBHelper.getJAXBContext(jc) .createObjectGraph("blog.objectgraphs.dynamic.Customer"); contactInfo.addAttributeNodes("name"); Subgraph location = contactInfo.addSubgraph("billingAddress"); location.addAttributeNodes("city", "province"); Subgraph simple = contactInfo.addSubgraph("phoneNumbers"); simple.addAttributeNodes("value");// Output XML - Based on Object Graph marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, contactInfo); marshaller.marshal(customer, System.out);// Output JSON - Based on Object Graph marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json"); marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false); marshaller.setProperty(MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); marshaller.marshal(customer, System.out); }} Input/Output The following input and output are the same for both the metadata driven and programmatic demos. input.xml/Output We will use the following document to populate our domain model.  We will also marshal it back out to demonstrate that all of the content is actually mapped. <?xml version="1.0" encoding="UTF-8"?> <customer id="123"> <name>Jane Doe</name> <billingAddress> <street>1 A Street</street> <city>Any Town</city> <province>Ontario</province> <postalCode>A1B 2C3</postalCode> </billingAddress> <shippingAddress> <street>2 B Road</street> <city>Another Place</city> <province>Quebec</province> <postalCode>X7Y 8Z9</postalCode> </shippingAddress> <phoneNumbers> <phoneNumber type="work">555-1111</phoneNumber> <phoneNumber type="home">555-2222</phoneNumber> </phoneNumbers> </customer> XML Output Based on Object Graph The XML below was produced by the exact same model as the previous XML document.  The difference is that we leveraged an object graph to select a subset of the mapped content. <?xml version="1.0" encoding="UTF-8"?> <customer> <name>Jane Doe</name> <billingAddress> <city>Any Town</city> <province>Ontario</province> </billingAddress> <phoneNumbers> <phoneNumber>555-1111</phoneNumber> <phoneNumber>555-2222</phoneNumber> </phoneNumbers> </customer> JSON Output Based on Object Graph Below is the same subset as the previous XML document represented as JSON.  We have used the new JSON_WRAPPER_AS_ARRAY_NAME property (see Binding to JSON & XML – Handling Collections ) to improve the representation of collection values. { "name" : "Jane Doe", "billingAddress" : { "city" : "Any Town", "province" : "Ontario" }, "phoneNumbers" : [ "555-1111", "555-2222" ] }   Reference: MOXy’s Object Graphs & Dynamic JAXB from our JCG partner Blaise Doughan at the Java XML & JSON Binding blog. ...
Java Code Geeks and all content copyright © 2010-2015, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

Get ready to Rock!
To download the books, please verify your email address by following the instructions found on the email we just sent you.

THANK YOU!

Close