Tuesday, September 10, 2013

Mix JAXBContext for Marshalling

Suppose you have one xml document like this

<product>
  <name>MicroWave</name>
 <extra>
   <!-- undefined xml content from other source -->
 </extra>
</product>
The xml document will be generated by JAXB marshaller(A).

Suppose the XML content enclosed by extra tag is from another JAXB marshaller(B), how can we insert the result from B to the location under Extra.

First, define the extra has the type xsd:anyType. You can do this in schema, annotation. For eclipselink xom, your property will be xml-anyelement instead of the regular xml-element.

Second, define a XmlAdapter which will use the unmarshaller B to convert java object into a org.w3c.dom.Element. The Element will be marshalled in place.

public class ObjectAdapter extends XmlAdapter<Element, Object>
{
 
    @Override
    public Element marshal(Object arg0) throws Exception
    {
        if (arg0==null)
        {
            return null;
        }
        Class<?> cls = arg0.getClass();
        JAXBContext context = JAXBContext.newInstance(cls);
        Marshaller marshaller = context.createMarshaller();

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.newDocument();
        Element root = doc.createElement("object");
        root.setAttribute("cls", cls.getName());

        marshaller.setProperty("jaxb.fragment", true);
        marshaller.marshal(arg0, root);
       
           return root;
    }

    public Element getFirstElement(Element element)
    {
        for (int i = 0; i < element.getChildNodes().getLength(); i++)
        {
            Node child = element.getChildNodes().item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE)
            {
                return (Element) child;
            }

        }
        return null;
    }

    @Override
    public Object unmarshal(Element element) throws Exception
    {
        if (element==null)
        {
            return null;
        }
        Element firstElement=getFirstElement(element);
        if (firstElement==null)
        {
            return null;
        }
        String clzName = element.getAttribute("cls");
        Class<?> cls = Class.forName(clzName);

        JAXBContext context = JAXBContext.newInstance(cls);
        Unmarshaller um = context.createUnmarshaller();

        Object object = um.unmarshal(firstElement);
        return object;
    }
}

Finally attach the XmlAdapter to property through configuration or annotation.



Tuesday, September 3, 2013

Control JSF tree building process

When I use h:selectOneRadio, I really do not  like its layout. Sometime, I also want to change the layout of summary message and detail message from FacesMessage. But I end up surviving with what is from the library. It is very tough to adding a renderer for these issues.

Here is another similar question:Suppose we have a composite component chain like this A->B->C. We like to use A in our final page. But, we like to customize the layout of C which is not exposed by B and A.  Passing the composite:attribute from leaf composite component to top composite component is not an option. We could end up with so many irrelevant attributes at top component.

Actually, JSTL core tag provides a very good way to control component building. However, using it is discouraged from most JSF developer. The core issue is that JSF does not have good building support.  Here is a solution for this http://code.google.com/p/jsf2utils/wiki/buildContext

Painless JSF Internalization

This is how I usually handle I18N request for a project. In the very beginning, it is definitely a low priority. First, I do not know whether the project can be successful or not. Second, the project may target for customer in one region in the beginning. We have time constraint and need to finish all the important function first.

Sometime late, we need to support i18N. I need to go through every constant string in java code, facelet xhmtl file to find out all of them, and save them in property files. Each Message has an well-assigned message key. If I missed one string at release time, I have postpone that string to next release. That sucks, isn't it?  Once I have finish this, I need to carefully maintain the property file. This process is time-consuming and require some strict discipline.

Moreover, in some dynamic system, the constant string is no known at develop time. property file approach is completely useless in these situations.

This library provides a solution that handle i18N at background. Both developers and end users can participate the i18N process.

Finally, I am tired to translate 'Save' so many times in so any projects.

Here, I introduce a library which play magic at background.  Developer no needs to worry about the i18n issue. It can be handled at any time with ease.

Please view my project http://code.google.com/p/jsfi18n/