Fix issue 64: ClassCastException in Representer when working with ParameterizedType
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 2380dc9..4d7c2c8 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -7,6 +7,9 @@
 	</properties>

 	<body>

 		<release version="1.7" date="in Mercurial" description="development">

+		    <action dev="py4fun" type="fix" issue="64" due-to="maxim.moschko">

+                ClassCastException in Representer when working with ParameterizedType (2010-04-25)

+            </action>

 	        <action dev="py4fun" type="update">

                 Improve toString() method for Node. Since scalars cannot be recursive

                 they can be printed (2010-04-15)

diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
index c0e74fc..618d4d1 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
@@ -21,7 +21,6 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.ArrayList;
@@ -268,7 +267,7 @@
                     if (!typeDetected && valueNode.getNodeId() != NodeId.scalar) {
                         // only if there is no explicit TypeDescription
                         Type[] arguments = property.getActualTypeArguments();
-                        if (arguments != null && !(arguments[0] instanceof TypeVariable)) {
+                        if (arguments != null) {
                             // TODO check non Java HotSpot(TM) Server VM
                             // type safe (generic) collection may contain the
                             // proper class
diff --git a/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java b/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java
index b2cd78a..3f9362d 100644
--- a/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java
+++ b/src/main/java/org/yaml/snakeyaml/introspector/MethodProperty.java
@@ -18,6 +18,7 @@
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -37,6 +38,7 @@
         property.getWriteMethod().invoke(object, value);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public Type[] getActualTypeArguments() {
         if (List.class.isAssignableFrom(property.getPropertyType())
@@ -45,7 +47,13 @@
             if (property.getReadMethod().getGenericReturnType() instanceof ParameterizedType) {
                 ParameterizedType grt = (ParameterizedType) property.getReadMethod()
                         .getGenericReturnType();
-                return grt.getActualTypeArguments();
+                Type[] result = grt.getActualTypeArguments();
+                if (result == null || (result[0] instanceof TypeVariable)
+                        || (result[0] instanceof ParameterizedType)) {
+                    return null;
+                } else {
+                    return result;
+                }
             } else {
                 return null;
             }
diff --git a/src/main/java/org/yaml/snakeyaml/representer/Representer.java b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
index 5fb4bb9..dc049cd 100644
--- a/src/main/java/org/yaml/snakeyaml/representer/Representer.java
+++ b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
@@ -21,7 +21,6 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -179,7 +178,7 @@
     @SuppressWarnings("unchecked")
     protected void checkGlobalTag(Property property, Node node, Object object) {
         Type[] arguments = property.getActualTypeArguments();
-        if (arguments != null && !(arguments[0] instanceof TypeVariable)) {
+        if (arguments != null) {
             if (node.getNodeId() == NodeId.sequence) {
                 // apply map tag where class is the same
                 Class<? extends Object> t = (Class<? extends Object>) arguments[0];
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue64/MethodDesc.java b/src/test/java/org/yaml/snakeyaml/issues/issue64/MethodDesc.java
new file mode 100644
index 0000000..96328f9
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue64/MethodDesc.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2008-2010 Andrey Somov
+ *
+ * Licensed 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.yaml.snakeyaml.issues.issue64;
+
+import java.util.List;
+
+public class MethodDesc {
+    private String name;
+    private List<Class<?>> argTypes;
+
+    public MethodDesc() {
+    }
+
+    public MethodDesc(String name, List<Class<?>> argTypes) {
+        this.name = name;
+        this.argTypes = argTypes;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<Class<?>> getArgTypes() {
+        return argTypes;
+    }
+
+    public void setArgTypes(List<Class<?>> argTypes) {
+        this.argTypes = argTypes;
+    }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue64/ParameterizedTypeTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue64/ParameterizedTypeTest.java
new file mode 100644
index 0000000..8f31985
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue64/ParameterizedTypeTest.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2008-2010 Andrey Somov
+ *
+ * Licensed 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.yaml.snakeyaml.issues.issue64;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Dumper;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Loader;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.ScalarNode;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+public class ParameterizedTypeTest extends TestCase {
+
+    public void testRepresenter() {
+        Yaml yaml = new Yaml(new Loader(new ClassConstructor()), new Dumper(new ClassRepresenter(),
+                new DumperOptions()));
+
+        String methodName = "testMethod";
+        List<Class<?>> argTypes = new LinkedList<Class<?>>();
+        argTypes.add(String.class);
+        argTypes.add(Integer.class);
+        argTypes.add(Boolean.class);
+        MethodDesc methodDesc = new MethodDesc(methodName, argTypes);
+
+        String out = yaml.dump(methodDesc);
+        // System.out.println(out);
+        assertEquals(
+                "!!org.yaml.snakeyaml.issues.issue64.MethodDesc\nargTypes: [!clazz 'String', !clazz 'Integer', !clazz 'Boolean']\nname: testMethod\n",
+                out);
+        MethodDesc parsed = (MethodDesc) yaml.load(out);
+        assertEquals(methodName, parsed.getName());
+        List<Class<?>> argTypes2 = parsed.getArgTypes();
+        assertEquals(3, argTypes2.size());
+        assertEquals(argTypes, argTypes2);
+    }
+
+    static class ClassRepresenter extends Representer {
+        public ClassRepresenter() {
+            this.representers.put(Class.class, new RepresentClass());
+        }
+
+        private class RepresentClass implements Represent {
+            public Node representData(Object data) {
+                Class<?> clazz = (Class<?>) data;
+                return representScalar(new Tag("!clazz"), clazz.getSimpleName());
+            }
+        }
+    }
+
+    static class ClassConstructor extends Constructor {
+        public ClassConstructor() {
+            this.yamlConstructors.put(new Tag("!clazz"), new ConstructClass());
+        }
+
+        private class ConstructClass extends AbstractConstruct {
+
+            public Object construct(Node node) {
+                String clazz = (String) constructScalar((ScalarNode) node);
+                try {
+                    return Class.forName("java.lang." + clazz);
+                } catch (ClassNotFoundException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+}