You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by si...@apache.org on 2010/06/26 19:07:08 UTC

svn commit: r958243 - in /cocoon/cocoon3/trunk/cocoon-optional/src: main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/ test/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/

Author: simonetripodi
Date: Sat Jun 26 17:07:07 2010
New Revision: 958243

URL: http://svn.apache.org/viewvc?rev=958243&view=rev
Log:
added the collection generic type support

Added:
    cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java   (with props)
Modified:
    cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGenerator.java
    cocoon/cocoon3/trunk/cocoon-optional/src/test/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGeneratorTestCase.java

Added: cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java?rev=958243&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java (added)
+++ cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java Sat Jun 26 17:07:07 2010
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cocoon.optional.pipeline.components.sax.jaxb;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * @version $Id$
+ */
+class GenericUtils {
+
+    /**
+     * This class can't be instantiated.
+     */
+    private GenericUtils() {
+        // do nothing
+    }
+
+    /**
+     * Returns the type from super class's type parameter.
+     */
+    public static Type getSuperclassTypeParameter(Class<?> subclass) {
+        Type superclass = subclass.getGenericSuperclass();
+        if (!(superclass instanceof ParameterizedType)) {
+            throw new RuntimeException("Missing type parameter.");
+        }
+        ParameterizedType parameterized = (ParameterizedType) superclass;
+        return parameterized.getActualTypeArguments()[0];
+    }
+
+    /**
+     * Get the class of the parameter of the provided parameterized type. If the
+     * type is a Class, then <code>null</code> is returned. If the type is
+     * ParameterizedType, then the actual type argument is returned.
+     * <p>
+     * E.g. if type is <code>String.class</code>, then <code>null</code> is
+     * returned. If type is <code>List&lt;String&gt;</code>, then
+     * <code>String.class</code> is returned.
+     * <p>
+     * In case the type has more than one parameter, only the type of the first
+     * parameter is returned by this method.
+     * 
+     * @param type the type to return the class of the parameter for
+     * @return the class of the generic parameter of type
+     */
+    public static Class<?> getGenericParamType(Type type) {
+        Class<?> generic = null;
+        if (type instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+            generic = (Class<?>) actualTypeArguments[0];
+        }
+        return generic;
+    }
+}

Propchange: cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/GenericUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGenerator.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGenerator.java?rev=958243&r1=958242&r2=958243&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGenerator.java (original)
+++ cocoon/cocoon3/trunk/cocoon-optional/src/main/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGenerator.java Sat Jun 26 17:07:07 2010
@@ -18,6 +18,8 @@
  */
 package org.apache.cocoon.optional.pipeline.components.sax.jaxb;
 
+import java.lang.reflect.Type;
+
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
@@ -32,7 +34,7 @@ import org.xml.sax.helpers.AttributesImp
 /**
  * SAX generator that produces SAX events from Object using the JAXB marshaller.
  */
-public final class JAXBGenerator extends AbstractSAXGenerator implements CachingPipelineComponent {
+public abstract class JAXBGenerator<T> extends AbstractSAXGenerator implements CachingPipelineComponent {
 
     private static final String DEFAULT = "##default";
 
@@ -42,17 +44,36 @@ public final class JAXBGenerator extends
 
     private final InMemoryLRUMarshallerCache marshallerCache = InMemoryLRUMarshallerCache.getInstance();
 
-    private final Object toBeMarshalled;
+    private final T toBeMarshalled;
+
+    private final Class<?> type;
 
     private String charset = UTF_8;
 
     private boolean formattedOutput = false;
 
-    public JAXBGenerator(Object toBeMarshalled) {
+    private boolean pluralize = false;
+
+    public JAXBGenerator(T toBeMarshalled) {
         if (toBeMarshalled == null) {
             throw new IllegalArgumentException("Argument 'toBeMarshalled' must not be null");
         }
         this.toBeMarshalled = toBeMarshalled;
+        Class<?> rawType = toBeMarshalled.getClass();
+        // analyze generics for collections
+        if (Iterable.class.isAssignableFrom(rawType)) {
+            Type type = GenericUtils.getSuperclassTypeParameter(this.getClass());
+            if (type == null) {
+                throw new IllegalArgumentException("Generic type is not defined");
+            }
+            this.type = GenericUtils.getGenericParamType(type);
+            this.pluralize = true;
+        } else if (rawType.isArray()) { // else get array type
+            this.pluralize = true;
+            this.type = rawType.getComponentType();
+        } else { // otherwise is the passed argument type
+            this.type = rawType;
+        }
     }
 
     public String getCharset() {
@@ -71,26 +92,14 @@ public final class JAXBGenerator extends
         this.formattedOutput = formattedOutput;
     }
 
-    public void execute() {
+    public final void execute() {
         // retrieve the right type has to be marshaled
         String xmlRootElementName = null;
         String xmlRootElementNameSpace = null;
-        boolean pluralize = false;
-        Class<?> type = this.toBeMarshalled.getClass();
-
-        // analyze generics for collections
-        if (Iterable.class.isAssignableFrom(type)) {
-            pluralize = true;
-            // TODO extract the generic type!!!
-        } else if (type.isArray()) { // else get array type
-            pluralize = true;
-            type = type.getComponentType();
-        }
-        // otherwise is the passed argument type
 
         // validate the type can be marshaled using JAXB
-        if (!type.isAnnotationPresent(XmlRootElement.class)
-                && !type.isAnnotationPresent(XmlType.class)) {
+        if (!this.type.isAnnotationPresent(XmlRootElement.class)
+                && !this.type.isAnnotationPresent(XmlType.class)) {
             throw new IllegalArgumentException("Object of type "
                     + type.getName()
                     + " can't be marshalled since neither of "
@@ -101,14 +110,14 @@ public final class JAXBGenerator extends
         }
 
         // get the root element name if needed
-        if (pluralize) {
+        if (this.pluralize) {
             String name = null;
-            if (type.isAnnotationPresent(XmlRootElement.class)) {
-                XmlRootElement xmlRootElement = type.getAnnotation(XmlRootElement.class);
+            if (this.type.isAnnotationPresent(XmlRootElement.class)) {
+                XmlRootElement xmlRootElement = this.type.getAnnotation(XmlRootElement.class);
                 name = xmlRootElement.name();
                 xmlRootElementNameSpace = xmlRootElement.namespace();
-            } else if (type.isAnnotationPresent(XmlType.class)) {
-                XmlType xmlType = type.getAnnotation(XmlType.class);
+            } else if (this.type.isAnnotationPresent(XmlType.class)) {
+                XmlType xmlType = this.type.getAnnotation(XmlType.class);
                 name = xmlType.name();
                 xmlRootElementNameSpace = xmlType.namespace();
             }
@@ -123,20 +132,19 @@ public final class JAXBGenerator extends
                 xmlRootElementNameSpace = EMPTY;
             }
 
-            // pluralize
             // TODO has to be improved, see PluralStemmers reference impl
             xmlRootElementName += 's';
         }
 
         try {
-            Marshaller xmlMarshaller = marshallerCache.getMarshaller(type);
+            Marshaller xmlMarshaller = this.marshallerCache.getMarshaller(type);
             if (this.charset != null) {
                 xmlMarshaller.setProperty(Marshaller.JAXB_ENCODING, this.charset);
             }
             xmlMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, this.formattedOutput);
 
             // setup the Marshaler if a collection has to be marshaled
-            if (pluralize) {
+            if (this.pluralize) {
                 xmlMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
                 this.getSAXConsumer().startDocument();
                 this.getSAXConsumer().startElement(xmlRootElementNameSpace, xmlRootElementName, xmlRootElementName, new AttributesImpl());

Modified: cocoon/cocoon3/trunk/cocoon-optional/src/test/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGeneratorTestCase.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-optional/src/test/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGeneratorTestCase.java?rev=958243&r1=958242&r2=958243&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-optional/src/test/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGeneratorTestCase.java (original)
+++ cocoon/cocoon3/trunk/cocoon-optional/src/test/java/org/apache/cocoon/optional/pipeline/components/sax/jaxb/JAXBGeneratorTestCase.java Sat Jun 26 17:07:07 2010
@@ -21,6 +21,8 @@ package org.apache.cocoon.optional.pipel
 import static junit.framework.Assert.assertTrue;
 
 import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.cocoon.pipeline.NonCachingPipeline;
 import org.apache.cocoon.pipeline.Pipeline;
@@ -29,9 +31,12 @@ import org.apache.cocoon.sax.component.X
 import org.custommonkey.xmlunit.Diff;
 import org.junit.Test;
 
+/**
+ * $Id$
+ */
 public final class JAXBGeneratorTestCase {
 
-    // @Test
+    @Test
     public void testPipelineWithBean() throws Exception {
         Animal animal = new Animal();
         animal.setAge(5);
@@ -40,7 +45,8 @@ public final class JAXBGeneratorTestCase
         animal.setLatinName("Mustela putoris furo");
         animal.setName("Lector");
 
-        this.internalAssert(animal, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><animal><call>Dook</call><colour>albino</colour><latinName>Mustela putoris furo</latinName><name>Lector</name><age>5</age></animal>");
+        this.internalAssert(new JAXBGenerator<Animal>(animal) {},
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?><animal><call>Dook</call><colour>albino</colour><latinName>Mustela putoris furo</latinName><name>Lector</name><age>5</age></animal>");
     }
 
     @Test
@@ -52,13 +58,30 @@ public final class JAXBGeneratorTestCase
         animal.setLatinName("Mustela putoris furo");
         animal.setName("Lector");
 
-        this.internalAssert(new Animal[]{ animal, animal },
+        this.internalAssert(new JAXBGenerator<Animal[]>(new Animal[]{ animal, animal }) {},
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?><animals><animal><call>Dook</call><colour>albino</colour><latinName>Mustela putoris furo</latinName><name>Lector</name><age>5</age></animal><animal><call>Dook</call><colour>albino</colour><latinName>Mustela putoris furo</latinName><name>Lector</name><age>5</age></animal></animals>");
+    }
+
+    @Test
+    public void testPipelineWithBeanList() throws Exception {
+        Animal animal = new Animal();
+        animal.setAge(5);
+        animal.setCall("Dook");
+        animal.setColour("albino");
+        animal.setLatinName("Mustela putoris furo");
+        animal.setName("Lector");
+
+        List<Animal> animals = new ArrayList<Animal>();
+        animals.add(animal);
+        animals.add(animal);
+
+        this.internalAssert(new JAXBGenerator<List<Animal>>(animals) {},
                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><animals><animal><call>Dook</call><colour>albino</colour><latinName>Mustela putoris furo</latinName><name>Lector</name><age>5</age></animal><animal><call>Dook</call><colour>albino</colour><latinName>Mustela putoris furo</latinName><name>Lector</name><age>5</age></animal></animals>");
     }
 
-    private void internalAssert(Object toBeMarshalled, String expected) throws Exception {
+    private void internalAssert(JAXBGenerator<?> generator, String expected) throws Exception {
         Pipeline<SAXPipelineComponent> pipeline = new NonCachingPipeline<SAXPipelineComponent>();
-        pipeline.addComponent(new JAXBGenerator(toBeMarshalled));
+        pipeline.addComponent(generator);
         pipeline.addComponent(new XMLSerializer());
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();