Monday, February 27, 2012

SQL server - export xml to file

sp_makewebtask @outputfile = 'c:\temp\myxmlfile.xml',
    @query = 'SELECT ( SELECT  location AS loc,ChangeFreq AS changefreq,Priority AS priority from posterdata_sitemap FOR XML PATH(''url''),TYPE)', 
    @templatefile = 'c:\temp\template.tpl'



/*
EXEC master.dbo.sp_configure 'show advanced options', 1
RECONFIGURE
sp_configure 'Web Assistant Procedures', 1
RECONFIGURE */

Wednesday, February 22, 2012

xml file from SQL

http://blog.sqlauthority.com/2009/02/12/sql-server-simple-example-of-creating-xml-file-using-t-sql/

I always want to learn SQL Server and XML. Let us go over very simple example today about how to create XML using SQL Server.
Following is the XML which we want to create:
T-SQL Script to generate above XML:
SELECT ( SELECT 'White' AS Color1,
'Blue' AS Color2,
'Black' AS Color3,
'Light' AS 'Color4/@Special',
'Green' AS Color4,
'Red' AS Color5
FOR
XML PATH('Colors'),
TYPE
),
(
SELECT 'Apple' AS Fruits1,
'Pineapple' AS Fruits2,
'Grapes' AS Fruits3,
'Melon' AS Fruits4
FOR
XML PATH('Fruits'),
TYPE
)
FOR XML PATH(''),
ROOT('SampleXML')
GO

Tuesday, February 21, 2012

SQL server - generate sitemap table

Have you ever wondered why some of your site's pages are indexed by search engines while others are not? Using a sitemap you can tell search engines exactly where to find each of your site's pages. A sitemap is a file using XML that lists URLs for a site so that the site can be more accurately crawled by search engines.
The best news is that now you can specify the sitemap in your robots.txt file and Google's Webmaster Tools, MSN Live, and Yahoo all allow you to submit a site map URL when listing your site.
Here is an example sitemap.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>http://www.dotnetdesignguide.com/</loc>    
        <changefreq>daily</changefreq>
        <priority>0.5</priority>
    </url>
</urlset>

Unless you have a blog or CMS you have to manually update your sitemap 
every time you add a new page to your site.
   Because aspiring web developers never do anything manual we will 
create a dynamic sitemap using ASP.NET and SQL Server. The urls of the
   pages on our site will be stored in a SQL Server table and we'll 
create an ASP.Net page to display the XML syntax. Additionally we could 
take it a 
   step further and create navigation hyperlinks for our site or even 
content specific landing pages using the urls from the table

Step 1. SQL Server Table and Stored Procedure

First we create a table called "mysitemap". Open SQL Server and open a new query window in your database. Cut and paste the following SQL statement below to create the table. This table will store our data about the urls on our webite that we want search engines to find.
CREATE TABLE [dbo].[MySitemap](
  [ID] [int] IDENTITY(1,1) NOT NULL,
  [Location] [varchar](200) NULL,
  [ChangeFreq] [varchar](20) NULL CONSTRAINT [DF_MySitemap_ChangeFreq]  DEFAULT ('daily'),
  [Priority] [varchar](3) NULL CONSTRAINT [DF_MySitemap_Priority]  DEFAULT ((0.5)),
  [Category] [varchar](50) NULL,
 CONSTRAINT [PK_MySitemap] PRIMARY KEY CLUSTERED 
(
 [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

After adding some data your table should look similar to this with different urls of course.

SQL Table for storing Sitemap
Next keeping an eye on security and performance we'll create a SQL Server stored procedure called sp_mysitemap_select to query the urls from the table we just created. Be sure to assign execute permissions for this stored procedure to the sql login that your web site uses to query the database.
We are going to add a conditional statement to this stored procedure so that we can use it later on in the example to create navigation menus for the site as well. This way once we have a new page ready on the site all we have to do is add the url to the SQL table and it will be available in the navigation menu as well as the site map automatically.
CREATE  PROCEDURE [dbo].[sp_mysitemap_select] 
(
@category varchar(50)
)
AS

if (@category is null)
 begin
  select Location, ChangeFreq, Priority from mysitemap
  order by Category
 end
else
 begin
  select Location from mysitemap where Category=@category
 end
return


Being good programmers we always test our code on the database before hooking it into a web page so manually execute the store procedure we just created in a query window


Dynamic Sitemap using ASP.NET and SQL Server.
Dynamic Sitemap using ASP.NET and SQL Server.

Wednesday, February 15, 2012

java - noclassdeffounderror

http://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html

Although quite wiered, but for my case, this error was removed by logging in by a different user name. might be some startup program in my user profile which was disturbing jre.

this is how it works!

Friday, February 10, 2012

com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast

for me the error was resolved by this

@XmlAnyElement(lax = true)
public List<Foo> foos;

Java - Pass by value/Pass by reference

It is quite common that  fresh developer (incorrectly) state "primitives are passed by value, objects are passed by reference". The terms "pass-by-value" semantics and "pass-by-reference" semantics have very precise definitions, and they're often horribly abused when folks talk about Java.Let's correct it.

Java does manipulate objects by reference, and all object variables are references. However, Java doesn't pass method arguments by reference; it passes them by value.Take the badSwap() method for example:

public void badSwap(int var1, int var2)
{
  int temp = var1;
  var1 = var2;
  var2 = temp;
}

When badSwap() returns, the variables passed as arguments will still hold their original values. The method will also fail if we change the arguments type from int to Object. Now, here is where it gets tricky:

public void tricky(Point arg1, Point arg2)
{
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args)
{
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X: " + pnt1.x + " Y: " +pnt1.y);
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y); 
}


If we execute this main() method, we see the following output:

X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0

The method successfully alters the value of pnt1, even though it is passed by value; however, a swap of pnt1 and pnt2 fails! When you pass pnt1 and pnt2 to the tricky() method, Java passes the references by value just like any other parameter. This means the references passed to the method are actually copies of the original references. Figure  below shows two references pointing to the same object after Java passes an object to a method.

Moral:  Java always pass method arguments by value not by reference. In other words, always copies of arguments are sent to methods, in case of primitives, copies of primitives and in case of objects, the copies of references.

Thursday, February 9, 2012

@XmlTransient for handling Interfaces

I used @XmlTransient to fix the error of "Jaxb can not handle interface". I put this annotation on an the interface and it worked fine for me at least.
if you see any issue in it. please let me know.

Monday, February 6, 2012

JAXB - Mapping the unmappable

http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html

The XmlAdapter mechanism in JAXB ensures that there is no such thing as an unmappable class (with a little programmatic help). However there appears to be some confusion on how to use XmlAdapter, below is the general concept:

  1. Identify the unmappable class
  2. Create an equivalent class that is mappable
  3. Create an XmlAdapter to convert between unmappable and mappable objects
  4. Specify the XmlAdapter
Part of the problem may be due to the Javadocs on the XmlAdapter class. Below I'll flush out the example used there.


1. Identify the Unmappable Class

 In this example the unmappable class is java.util.Map.

2.  Create an Equivalent Class that is Mappable

Map could be represented by an object (MyMapType), that contained a list of objects with two properties: key and value (MyMapEntryType).

1
2
3
4
5
6
7
8
9
import java.util.ArrayList;
import java.util.List;
 
public class MyMapType {
 
   public List<MyMapEntryType> entry =
      new ArrayList<MyMapEntryType>();
 
}

and
1
2
3
4
5
6
7
8
9
10
11
12
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.XmlAttribute;
 
public class MyMapEntryType {
 
   @XmlAttribute
   public Integer key;
 
   @XmlValue
   public String value;
 
}

3. Create an XmlAdapter to Convert Between Unmappable and Mappable Objects


The XmlAdapter<ValueType, BoundType> class is responsible for converting between instances of the unmappable and mappable classes. Most people get confused between the value and bound types. The value type is the mappable class, and the bound type is the unmappable class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.annotation.adapters.XmlAdapter;
  
public final class MyMapAdapter extends
  
   XmlAdapter<MyMapType,Map<Integer, String>> {
  
   @Override
   public MyMapType marshal(Map<Integer, String> arg0) throws Exception {
      MyMapType myMapType = new MyMapType();
      for(Entry<Integer, String> entry : arg0.entrySet()) {
         MyMapEntryType myMapEntryType =
            new MyMapEntryType();
         myMapEntryType.key = entry.getKey();
         myMapEntryType.value = entry.getValue();
         myMapType.entry.add(myMapEntryType);
      }
      return myMapType;
   }
  
   @Override
   public Map<Integer, String> unmarshal(MyMapType arg0) throws Exception {
      HashMap<Integer, String> hashMap = new HashMap<Integer, String>();
      for(MyMapEntryType myEntryType : arg0.entry) {
         hashMap.put(myEntryType.key, myEntryType.value);
      }
      return hashMap;
   }
  
}

4. Specify the XmlAdapter

The @XmlJavaTypeAdapter annotation is used to specify the use of the XmlAdapter. Below it is specified on the map field on the Foo class. Now during marshal/unmarshal operations the instance of Map is treated as an instance of MyHashMapType.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {
 
   @XmlJavaTypeAdapter(MyMapAdapter.class)
   Map<Integer, String> map =
    new HashMap<Integer, String>();
 
   public Map getMap() {
      return map;
   }
 
   public void setMap(Map map) {
      this.map = map;
   }
 
}

In upcoming posts I'll describe extensions in the EclipseLink JAXB (MOXy) implementation that reduce the dependency on XmlAdapter.

Further Reading

If you enjoyed this post, then you may also be interested in:
  • JAXB and Immutable Objects
    In this post an XmlAdapter is used map a domain object with a mult-argument constructor and fields marked final.  This example also demonstrates how the @XmlJavaTypeAdapter annotation can be used at the type level.
  • @XmlTransformation - Going Beyond XmlAdapter
    In this post an EclipseLink MOXy extension (@XmlTransformation) is used instead of @XmlAdapter to provide a little more flexibility for an interesting use case.

JAX vs Extreme

http://blog.bdoughan.com/2010/10/how-does-jaxb-compare-to-xstream.html

How Does JAXB Compare to XStream?

The XStream FAQ states the following when being compared to JAXB:

JAXB is a Java binding tool. It generates Java code from a schema and you are able to transform from those classes into XML matching the processed schema and back. Note, that you cannot use your own objects, you have to use what is generated.
In this post I will provide an alternative answer to that question.


Java Model

We will use the following model for this example. The classes represent customer data. The get/set methods have been omitted to save space.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package comparison;
import java.util.ArrayList;
import java.util.List;
public class Customer {
private long id;
private String name;
private Address address;
private List<phonenumber> phoneNumbers;
public Customer() {
phoneNumbers = new ArrayList<PHONENUMBER>();
}
}
</PHONENUMBER>

1
2
3
4
5
6
7
8
package comparison;
public class Address {
private String city;
private String street;
}

1
2
3
4
5
6
7
8
package comparison;
public class PhoneNumber {
private String type;
private String number;
}

Customer Data

The following instance of Customer will be marshalled to XML using both JAXB and XStream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package comparison;
public class Data {
public static Customer CUSTOMER;
static {
CUSTOMER = new Customer();
CUSTOMER.setId(123);
CUSTOMER.setName("Jane Doe");
Address address = new Address();
address.setStreet("1 A Street");
address.setCity("Any Town");
CUSTOMER.setAddress(address);
PhoneNumber workPhoneNumber = new PhoneNumber();
workPhoneNumber.setType("work");
workPhoneNumber.setNumber("555-WORK");
CUSTOMER.getPhoneNumbers().add(workPhoneNumber);
PhoneNumber cellPhoneNumber = new PhoneNumber();
cellPhoneNumber.setType("cell");
cellPhoneNumber.setNumber("555-CELL");
CUSTOMER.getPhoneNumbers().add(cellPhoneNumber);
}
}

Marshal Code

This is the code we will use to convert the objects to XML.

XStream

The following code will be used to marshal the instance of Customer to an OutputStream. The XStream code is quite compact.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package comparison.xstream;
import com.thoughtworks.xstream.XStream;
import static comparison.Data.CUSTOMER;
public class XStreamDemo {
public static void main(String[] args) {
XStream xstream = new XStream();
xstream.autodetectAnnotations(true);
xstream.toXML(CUSTOMER, System.out);
}
}

JAXB

The following code will be used to marshal the instance of Customer to an OutputStream. A couple of differences are already apparent:
  1. A JAXBContext needs to be initialized on the binding metadata before the marshal operation can occur.
  2. Unlike XStream JAXB does not format the XML by default, so we will enable this feature.
  3. With no metadata specified we need to supply JAXB with a root element name (and namespace).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package comparison.jaxb;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import comparison.Customer;
import static comparison.Data.CUSTOMER;
public class JAXBDemo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
JAXBElement<Customer> jaxbElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, CUSTOMER);
marshaller.marshal(jaxbElement, System.out);
}
}

Default XML Output

First we will examine the XML output produced by both XStream and JAXB if no metadata is used to customize the output.

XStream

XStream will produce the following XML. Note some of the elements are named after the fully qualified class name.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<comparison.Customer>
<id>123</id>
<name>Jane Doe</name>
<address>
<city>Any Town</city>
<street>1 A Street</street>
</address>
<phoneNumbers>
<comparison.PhoneNumber>
<type>work</type>
<number>555-WORK</number>
</comparison.PhoneNumber>
<comparison.PhoneNumber>
<type>cell</type>
<number>555-CELL</number>
</comparison.PhoneNumber>
</phoneNumbers>
</comparison.Customer>
JAXB

JAXB produces the following XML. The representation is straight forward and more compact than the XStream representation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<customer>
<id>123</id>
<address>
<city>Any Town</city>
<street>1 A Street</street>
</address>
<name>Jane Doe</name>
<phoneNumbers>
<number>555-WORK</number>
<type>work</type>
</phoneNumbers>
<phoneNumbers>
<number>555-CELL</number>
<type>cell</type>
</phoneNumbers>
</customer>

Field Access

For this example we will configure our XML binding tools to interact directly with the fields (instance variables).

XStream

XStream uses field access by default.

JAXB

By default JAXB will access public fields and properties. We can configure JAXB to use field access with the following package level annotation:

1
2
3
4
5
@XmlAccessorType(XmlAccessType.FIELD)
package comparison;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

Renaming Elements

Next we will look at how to tweak the XML output using the appropriate mapping metadata. First we will rename some elements. As you will see the amount of configuration required is almost identical.

XStream

For XStream we will use @XStreamAlias to configure the root element, and @XStreamImplicit to configure the phoneNumbers property.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
@XStreamAlias("customer")
public class Customer {
private long id;
private String name;
private Address address;
@XStreamImplicit(itemFieldName="phone-number")
private List<PHONENUMBER> phoneNumbers;
public Customer() {
phoneNumbers = new ArrayList<PHONENUMBER>();
}
}
</PHONENUMBER></PHONENUMBER>

JAXB

For JAXB we will use @XmlRootElement to configure the root element, and @XmlElement to configure the phoneNumbers property.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer {
private long id;
private String name;
private Address address;
@XmlElement(name="phone-number")
private List<PHONENUMBER> phoneNumbers;
public Customer() {
phoneNumbers = new ArrayList<PHONENUMBER>();
}
}
</PHONENUMBER></PHONENUMBER>

Note: The JAXB Marshal code can now be simplified since we no longer need to supply the root element information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package comparison.jaxb;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import comparison.Customer;
import static comparison.Data.CUSTOMER;
public class JAXBDemo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(CUSTOMER, System.out);
}
}

XML Output

At this point the same XML is being produced by XStream and JAXB.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<customer>
<id>123</id>
<name>Jane Doe</name>
<address>
<city>Any Town</city>
<street>1 A Street</street>
</address>
<phone-number>
<type>work</type>
<number>555-WORK</number>
</phone-number>
<phone-number>
<type>cell</type>
<number>555-CELL</number>
</phone-number>
</customer>

Change the Order of Elements

We will tweak the document again to make sure that when marshalling an Address object the "street" element will always appear before the "city" element.

XStream

For XStream we will need to change our marshal code. The following is based on instructions given in the XStream FAQ:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package comparison.xstream;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.FieldDictionary;
import com.thoughtworks.xstream.converters.reflection.SortableFieldKeySorter;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;
import comparison.Address;
import static comparison.Data.CUSTOMER;
public class XStreamDemo {
public static void main(String[] args) {
SortableFieldKeySorter sorter = new SortableFieldKeySorter();
sorter.registerFieldOrder(Address.class, new String[] { "street", "city"});
FieldDictionary fieldDictionary = new FieldDictionary(sorter);
Sun14ReflectionProvider reflectionProvider = new Sun14ReflectionProvider(fieldDictionary);
XStream xstream = new XStream(reflectionProvider);
xstream.autodetectAnnotations(true);
xstream.toXML(CUSTOMER, System.out);
}
}

JAXB

For JAXB we can configure the ordering of elements right on the model class. We will use @XmlType to do this.

1
2
3
4
5
6
7
8
9
10
11
package comparison;
import javax.xml.bind.annotation.XmlType;
@XmlType(propOrder={"street", "city"})
public class Address {
private String city;
private String street;
}

XML Output

The XML output is the same for both JAXB and XStream.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<customer>
<id>123</id>
<name>Jane Doe</name>
<address>
<street>1 A Street</street>
<city>Any Town</city>
</address>
<phone-number>
<type>work</type>
<number>555-WORK</number>
</phone-number>
<phone-number>
<type>cell</type>
<number>555-CELL</number>
</phone-number>
</customer>

Mapping to an Attribute

Now we will look at how to tweak the XML output using the appropriate mapping metadata to produce XML attributes. As you will see the amount of configuration required is almost identical.

XStream

For XStream we will use @XStreamAsAttribute to configure the id property to be represented as an XML attribute.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package comparison;
import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
@XStreamAlias("customer")
public class Customer {
@XStreamAsAttribute
private long id;
private String name;
private Address address;
@XStreamImplicit(itemFieldName="phone-number")
private List<PHONENUMBER> phoneNumbers;
public Customer() {
phoneNumbers = new ArrayList<PHONENUMBER>();
}
}
</PHONENUMBER></PHONENUMBER>

JAXB

For JAXB we will use @XmlAttribute to configure the id property to be represented as an XML attribute.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package comparison;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer {
@XmlAttribute
private long id;
private String name;
private Address address;
@XmlElement(name="phone-number")
private List<PHONENUMBER> phoneNumbers;
public Customer() {
phoneNumbers = new ArrayList<PHONENUMBER>();
}
}
</PHONENUMBER></PHONENUMBER>

XML Output

The XML output is the same for both JAXB and XStream.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<customer id="123">
<name>Jane Doe</name>
<address>
<city>Any Town</city>
<street>1 A Street</street>
</address>
<phone-number>
<type>work</type>
<number>555-WORK</number>
</phone-number>
<phone-number>
<type>cell</type>
<number>555-CELL</number>
</phone-number>
</customer>

Mapping Objects to Simple Content

To compact our document even further we will map the PhoneNumber class to a complex type with simple content.

XStream

With XStream we can do this using a converter. Examples of creating converters can be found on the XStream website:
We can reference the converter on the phoneNumbers property using @XStreamConverter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package comparison;
import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
@XStreamAlias("customer")
public class Customer {
@XmlAttribute
private long id;
private String name;
private Address address;
@XStreamImplicit(itemFieldName="phone-number")
@XStreamConverter(PhoneNumberConverter.class)
private List<PHONENUMBER> phoneNumbers;
public Customer() {
phoneNumbers = new ArrayList<PHONENUMBER>();
}
}
</PHONENUMBER></PHONENUMBER>

The converter can be implemented as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package comparison;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
public class PhoneNumberConverter implements Converter {
public boolean canConvert(Class clazz) {
return PhoneNumber.class == clazz;
}
public void marshal(Object object, HierarchicalStreamWriter hsw, MarshallingContext mc) {
PhoneNumber phoneNumber = (PhoneNumber) object;
hsw.addAttribute("type", phoneNumber.getType());
hsw.setValue(phoneNumber.getNumber());
}
public Object unmarshal(HierarchicalStreamReader hsr, UnmarshallingContext uc) {
PhoneNumber phoneNumber = new PhoneNumber();
phoneNumber.setType(hsr.getAttribute("type"));
phoneNumber.setNumber(hsr.getValue());
return phoneNumber;
}
}

JAXB

For JAXB we will use the @XmlAttribute and @XmlValue annotations on the PhoneNumber class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package comparison;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;
public class PhoneNumber {
@XmlAttribute
private String type;
@XmlValue
private String number;
}

XML Output:

The XML output is the same for both JAXB and XStream.

1
2
3
4
5
6
7
8
9
<customer id="123">
<name>Jane Doe</name>
<address>
<street>1 A Street</street>
<city>Any Town</city>
</address>
<phone-number type="work">555-WORK</phone-number>
<phone-number type="cell">555-CELL</phone-number>
</customer>

Applying Namespaces

We will now namespace qualify the XML document.

XStream

Namespace support in XStream appears to be limited to the StaxDriver. For more information see:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package comparison.xstream;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.FieldDictionary;
import com.thoughtworks.xstream.converters.reflection.SortableFieldKeySorter;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;
import com.thoughtworks.xstream.io.xml.QNameMap;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import comparison.Address;
import static comparison.Data.CUSTOMER;
public class XStreamDemo {
public static void main(String[] args) {
QNameMap nsm = new QNameMap();
nsm.setDefaultNamespace("http://www.example.com");
StaxDriver staxDriver = new StaxDriver(nsm);
SortableFieldKeySorter sorter = new SortableFieldKeySorter();
sorter.registerFieldOrder(Address.class, new String[] { "street", "city"});
FieldDictionary fieldDictionary = new FieldDictionary(sorter);
Sun14ReflectionProvider reflectionProvider = new Sun14ReflectionProvider(fieldDictionary);
XStream xstream = new XStream(reflectionProvider, staxDriver);
xstream.autodetectAnnotations(true);
xstream.toXML(CUSTOMER, System.out);
}
}

Note: With this change I lost XML formatting, the following was produced.

1
2
<customer xmlns="http://www.example.com" id="123"><name>Jane Doe</name><address><street>1 A Street</street><city>Any Town</city></address><phone-number type="work">555-WORK</phone-number><phone-number type="cell">555-CELL</phone-number></customer>

JAXB

We can configure the namespace information using the @XmlSchema package level annotation:
1
2
3
4
5
6
7
8
9
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSchema(namespace="http://www.example.com",
elementFormDefault=XmlNsForm.QUALIFIED)
package comparison;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

The following XML was produced

1
2
3
4
5
6
7
8
9
<customer xmlns="http://www.example.com" id="123">
<name>Jane Doe</name>
<address>
<street>1 A Street</street>
<city>Any Town</city>
</address>
<phone-number type="work">555-WORK</phone-number>
<phone-number type="cell">555-CELL</phone-number>
</customer>