scheu 02/05/24 14:34:22 Modified: java/src/org/apache/axis/encoding/ser BeanSerializer.java SimpleSerializer.java java/src/org/apache/axis/utils BeanUtils.java java/src/org/apache/axis/wsdl/fromJava Types.java java/src/org/apache/axis/wsdl/symbolTable SchemaUtils.java Utils.java java/test/wsdl/roundtrip Investment.java RoundtripTestServiceTestCase.java Log: While looking at defect http://nagoya.apache.org/bugzilla/show_bug.cgi?id=9261 I found a number of problems, which are fixed here. First I attempted to run Java2WSDL on the comprehensive test TestType SEI. This revealed a number of roundtripping problems with Attributes. Change 1 --------- The serialization code was using Types.isSimpleSchemaType(class) to determine if it an object was acceptable as an attribute. I added a new method Types.isAcceptableAsAttribute(class) which checks to see if the class is a simple type, an enumeration type or an extension of SimpleType. I changed all appropriate code to use the new isAcceptableAsAttribute method. -------------- This revealed a problem in the detection of enumeration classes. Change 2 -------- I updated the Types.isEnumClass(class) method to comply with the latest version of JSR 101. -------------- This revealed a problem with WSDL2Java for an attribute that was declared in the wsdl file using an anonymous type. Change 3 -------- Added a getAttributeAnonQName method that is similar to the existing getElementAnonQName method. Made corresponding changes to the symbolTable classes to use this method so that an attribute can be declared with an anonymous type. Cool! Also opened a defect indicating that we still need to support the "form" attributes for attributes. --------------- I then added a public static field to Investment.java in the roundtrip testcase to determine whether it is illegally mapped. It was... Change 4 -------- Small change to BeanUtils to prevent static, final and transient fields from being mapped to the properties. Added code to the roundtrip testcase to fail if such a mapping is found. Also added code to the roundtrip testcase to fail if a private field is mapped to wsdl. Revision Changes Path 1.32 +2 -2 xml-axis/java/src/org/apache/axis/encoding/ser/BeanSerializer.java Index: BeanSerializer.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/ser/BeanSerializer.java,v retrieving revision 1.31 retrieving revision 1.32 diff -u -r1.31 -r1.32 --- BeanSerializer.java 14 May 2002 23:46:34 -0000 1.31 +++ BeanSerializer.java 24 May 2002 21:34:21 -0000 1.32 @@ -357,11 +357,11 @@ Element where) throws Exception { // Attribute must be a simple type. - if (!types.isSimpleSchemaType(fieldType)) + if (!types.isAcceptableAsAttribute(fieldType)) { throw new AxisFault(JavaUtils.getMessage("AttrNotSimpleType00", fieldName, fieldType.getName())); - + } String elementType = types.writeType(fieldType); Element elem = types.createAttributeElement(fieldName, elementType, 1.14 +6 -5 xml-axis/java/src/org/apache/axis/encoding/ser/SimpleSerializer.java Index: SimpleSerializer.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/ser/SimpleSerializer.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- SimpleSerializer.java 28 Apr 2002 18:10:56 -0000 1.13 +++ SimpleSerializer.java 24 May 2002 21:34:21 -0000 1.14 @@ -270,11 +270,12 @@ // write attribute element Class fieldType = propertyDescriptor[i].getType(); - // Attribute must be a simple type. - if (!types.isSimpleSchemaType(fieldType)) + // Attribute must be a simple type, enum or SimpleType + if (!types.isAcceptableAsAttribute(fieldType)) { throw new AxisFault(JavaUtils.getMessage("AttrNotSimpleType00", propName, fieldType.getName())); + } // write attribute element // TODO the attribute name needs to be preserved from the XML @@ -291,11 +292,11 @@ BeanPropertyDescriptor bpd = propertyDescriptor[i]; Class type = bpd.getType(); - // Attribute must extend a simple type. - if (!types.isSimpleSchemaType(type)) + // Attribute must extend a simple type, enum or SimpleType + if (!types.isAcceptableAsAttribute(type)) { throw new AxisFault(JavaUtils.getMessage("AttrNotSimpleType01", type.getName())); - + } base = types.writeType(type); extension.setAttribute("base", base); } 1.5 +18 -16 xml-axis/java/src/org/apache/axis/utils/BeanUtils.java Index: BeanUtils.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/utils/BeanUtils.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- BeanUtils.java 3 May 2002 17:41:19 -0000 1.4 +++ BeanUtils.java 24 May 2002 21:34:21 -0000 1.5 @@ -255,23 +255,25 @@ // add it if not. for (int i=0; i < fields.length; i++) { Field f = fields[i]; - // skip field if it is declared final - if (Modifier.isFinal(f.getModifiers())) - continue; - String fName = f.getName(); - boolean found = false; - for (int j=0; j<pd.size() && !found; j++) { - String pName = - ((BeanPropertyDescriptor)pd.get(i)).getName(); - if (pName.length() == fName.length() && - pName.substring(0,1).equalsIgnoreCase( - fName.substring(0,1))) { - found = pName.length() == 1 || - pName.substring(1).equals(fName.substring(1)); + // skip field if it is final, transient, or static + if (!(Modifier.isStatic(f.getModifiers()) || + Modifier.isFinal(f.getModifiers()) || + Modifier.isTransient(f.getModifiers()))) { + String fName = f.getName(); + boolean found = false; + for (int j=0; j<pd.size() && !found; j++) { + String pName = + ((BeanPropertyDescriptor)pd.get(j)).getName(); + if (pName.length() == fName.length() && + pName.substring(0,1).equalsIgnoreCase( + fName.substring(0,1))) { + found = pName.length() == 1 || + pName.substring(1).equals(fName.substring(1)); + } + } + if (!found) { + pd.add(new BeanPropertyDescriptor(f.getName(), f)); } - } - if (!found) { - pd.add(new BeanPropertyDescriptor(f.getName(), f)); } } } 1.27 +48 -15 xml-axis/java/src/org/apache/axis/wsdl/fromJava/Types.java Index: Types.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/fromJava/Types.java,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- Types.java 24 May 2002 18:11:12 -0000 1.26 +++ Types.java 24 May 2002 21:34:21 -0000 1.27 @@ -60,6 +60,7 @@ import org.apache.axis.Constants; import org.apache.axis.encoding.Serializer; import org.apache.axis.encoding.SerializerFactory; +import org.apache.axis.encoding.SimpleType; import org.apache.axis.encoding.TypeMapping; import org.apache.axis.encoding.ser.BeanSerializerFactory; import org.apache.axis.utils.JavaUtils; @@ -429,22 +430,29 @@ try { java.lang.reflect.Method m = cls.getMethod("getValue", null); java.lang.reflect.Method m2 = cls.getMethod("toString", null); - java.lang.reflect.Method m3 = - cls.getMethod("fromString", - new Class[] {java.lang.String.class}); - - if (m != null && m2 != null && m3 != null && - cls.getMethod("fromValue", - new Class[] {m.getReturnType()}) != null) { - try { - if (cls.getMethod("setValue", - new Class[] {m.getReturnType()}) == null) + if (m != null && m2 != null) { + java.lang.reflect.Method m3 = + cls.getDeclaredMethod("fromString", + new Class[] {java.lang.String.class}); + java.lang.reflect.Method m4 = + cls.getDeclaredMethod("fromValue", + new Class[] {m.getReturnType()}); + + if (m3 != null && + Modifier.isStatic(m3.getModifiers()) && + Modifier.isPublic(m3.getModifiers()) && + m4 != null && + Modifier.isStatic(m4.getModifiers()) && + Modifier.isPublic(m4.getModifiers())) { + // Return false if there is a setValue member method + try { + if (cls.getMethod("setValue", + new Class[] {m.getReturnType()}) == null) + return true; + return false; + } catch (java.lang.NoSuchMethodException e) { return true; - return false; - } catch (java.lang.NoSuchMethodException e) { - // getValue & fromValue exist. setValue does not exist. - // Thus return true. - return true; + } } } } catch (java.lang.NoSuchMethodException e) {} @@ -621,6 +629,31 @@ isSimpleSoapEncodingType(type)); } + /** + * Is the given class acceptable as an attribute + * @param type input Class + * @return true if the type is a simple, enum type or extends SimpleType + */ + public boolean isAcceptableAsAttribute(Class type) { + return isSimpleType(type) || + isEnumClass(type) || + implementsSimpleType(type); + } + + /** + * Does the class implement SimpleType + * @param type input Class + * @return true if the type implements SimpleType + */ + boolean implementsSimpleType(Class type) { + Class[] impls = type.getInterfaces(); + for(int i=0; i<impls.length; i++) { + if (impls[i] == SimpleType.class) { + return true; + } + } + return false; + } /** * Generates a unique element name for a given namespace of the form * el0, el1 .... 1.3 +35 -1 xml-axis/java/src/org/apache/axis/wsdl/symbolTable/SchemaUtils.java Index: SchemaUtils.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/symbolTable/SchemaUtils.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- SchemaUtils.java 17 May 2002 19:09:33 -0000 1.2 +++ SchemaUtils.java 24 May 2002 21:34:22 -0000 1.3 @@ -408,6 +408,29 @@ } /** + * Returns the WSDL2Java QName for the anonymous type of the attribute + * or null. + */ + public static QName getAttributeAnonQName(Node node) { + QName nodeKind = Utils.getNodeQName(node); + if (nodeKind != null && + nodeKind.getLocalPart().equals("attribute") && + Constants.isSchemaXSD(nodeKind.getNamespaceURI())) { + NodeList children = node.getChildNodes(); + for (int j = 0; j < children.getLength(); j++) { + QName kind = Utils.getNodeQName(children.item(j)); + if (kind != null && + (kind.getLocalPart().equals("complexType") || + kind.getLocalPart().equals("simpleType")) && + Constants.isSchemaXSD(kind.getNamespaceURI())) { + return Utils.getNodeNameQName(children.item(j)); + } + } + } + return null; + } + + /** * If the specified node is a simple type or contains simpleContent, return true */ public static boolean isSimpleTypeOrSimpleContent(Node node) { @@ -1025,8 +1048,19 @@ // type QName typeAttr = Utils.getNodeTypeRefQName(child, "type"); + if (typeAttr == null) { + // Could be defined as an anonymous type + typeAttr = getAttributeAnonQName(child); + } + + // Get the corresponding TypeEntry TypeEntry type = symbolTable.getTypeEntry(typeAttr, false); - // name + + // Need to add code here to get the qualified or unqualified + // name. Similar to the code around line 350 for elenments. + // Rich Scheuerle + + // Now get the name. QName name = Utils.getNodeNameQName(child); // add type and name to vector, skip it if we couldn't parse it // XXX - this may need to be revisited. 1.3 +10 -1 xml-axis/java/src/org/apache/axis/wsdl/symbolTable/Utils.java Index: Utils.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/symbolTable/Utils.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Utils.java 17 May 2002 19:09:33 -0000 1.2 +++ Utils.java 24 May 2002 21:34:22 -0000 1.3 @@ -350,7 +350,8 @@ if (getAttribute(node, "ref") == null && getAttribute(node, "base") == null && getAttribute(node, "element") == null && - SchemaUtils.getElementAnonQName(node) == null) { + SchemaUtils.getElementAnonQName(node) == null && + SchemaUtils.getAttributeAnonQName(node) == null) { QName nodeName = getNodeQName(node); if (nodeName != null && Constants.isSchemaXSD(nodeName.getNamespaceURI()) && @@ -520,6 +521,14 @@ } } + // Get the anonymous type of an attribute + anonQName = SchemaUtils.getAttributeAnonQName(node); + if (anonQName != null) { + TypeEntry anonType = symbolTable.getType(anonQName); + if (anonType != null && !types.contains(anonType)) { + types.add(anonType); + } + } // Process extended types TypeEntry extendType = SchemaUtils.getComplexElementExtensionBase(node, symbolTable); if (extendType != null) { 1.3 +2 -1 xml-axis/java/test/wsdl/roundtrip/Investment.java Index: Investment.java =================================================================== RCS file: /home/cvs/xml-axis/java/test/wsdl/roundtrip/Investment.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Investment.java 20 Mar 2002 21:43:52 -0000 1.2 +++ Investment.java 24 May 2002 21:34:22 -0000 1.3 @@ -67,9 +67,10 @@ */ public abstract class Investment implements java.io.Serializable { + public static int dontMapToWSDL; // This should not be mapped to the WSDL public String name; private int id; - private double avgYearlyReturn; + private double avgYearlyReturn; // This should not be mapped to the WSDL public Investment() { 1.8 +20 -0 xml-axis/java/test/wsdl/roundtrip/RoundtripTestServiceTestCase.java Index: RoundtripTestServiceTestCase.java =================================================================== RCS file: /home/cvs/xml-axis/java/test/wsdl/roundtrip/RoundtripTestServiceTestCase.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- RoundtripTestServiceTestCase.java 3 Apr 2002 15:28:36 -0000 1.7 +++ RoundtripTestServiceTestCase.java 24 May 2002 21:34:22 -0000 1.8 @@ -61,6 +61,7 @@ import java.math.BigInteger; import java.math.BigDecimal; +import java.lang.reflect.Method; import junit.framework.TestCase; @@ -143,6 +144,25 @@ 201.25F, lastTradePrice, FLOAT_DELTA); + // Make sure static field dontMapToWSDL is not mapped. + try { + Method m = (StockInvestment.class). + getDeclaredMethod("getDontMapToWSDL", + new Class[] {}); + fail("Should not map static member dontMapToWSDL"); + } catch (NoSuchMethodException e) { + // Cool the method should not be in the class + } + + // Make sure private field avgYearlyReturn is not mapped. + try { + Method m = (StockInvestment.class). + getDeclaredMethod("getAvgYearlyReturn", + new Class[] {}); + fail("Should not map private member avgYearlyReturn"); + } catch (NoSuchMethodException e) { + // Cool the method should not be in the class + } } catch (RemoteException re) { fail("Remote Exception caught: " + re); }