[ http://issues.apache.org/jira/browse/XMLBEANS-207?page=all ]
Denis Anisimov updated XMLBEANS-207: ------------------------------------ Attachment: SchemaTypeCodePrinter.java SchemaTypeImpl.java SchemaTypeSystemCompiler.java > Big issue with bad validation of interfaces when .xsdconfig file is used > ------------------------------------------------------------------------ > > Key: XMLBEANS-207 > URL: http://issues.apache.org/jira/browse/XMLBEANS-207 > Project: XMLBeans > Type: Bug > Components: Compiler > Versions: Version 2 > Reporter: Denis Anisimov > Attachments: InterfaceExtensionImpl.java, SchemaTypeCodePrinter.java, > SchemaTypeImpl.java, SchemaTypeSystemCompiler.java > > The main problem here is inside InterfaceExtensionImpl when methods > validateMethods() and validateMethod() are called. > The perform validation against just interface without any knowing of bean > schema class which will be used for extention. > Lets imagine the situation when schema have type "tOne" and "tTwo" and "tTwo" > extends "tOne" > <complexType name="tTwo"> > <complexContent> > <extension base="tOne"/> > </complexContent> > </complexType> > In this case generated bean TOne will extends TTwo. > I want to create extention for TOne and TTwo. I want: TOne extends interface > First, TTwo extends interface Second. But also I want to keep original > schema hierarchy , so I want also interface Second extends First. > Original implementation doesn't allow to me handle this situation : see bug > http://issues.apache.org/jira/browse/XMLBEANS-205. > If this bug will be resolved then anyway I will need to create corresponding > methods in SecondHandler methods that will be responsible for > delegation methods from First interface because all methods in First > interface also exist in Second. BUT TTwo already extends TOne and > I don't need to create static methods for delegation them from First > interface. They already exists in TTwo because it originally extends TOne. > And > those methods delegated already in handler for First. But configuration file > knows nothing about schema extentions and validate methiods just against > handlers and interfaces as couple. So we have the problem. > I suggest some changes in InterfaceExtensionImpl.java, SchemaTypeImpl.java, > SchemaTypeSystemCompiler.java. > Possibly this is not best fix but it works and more appropriate fix wil need > changes in architecture...... > ( I suggest that bug http://issues.apache.org/jira/browse/XMLBEANS-205 > already fixed as described ) > ( changes marked with "!" ) > changes in SchemaTypeSystemCompiler.java : > public static boolean generateTypes(SchemaTypeSystem system, Filer filer, > XmlOptions options) > { > // partial type systems not allowed to be saved > if (system instanceof SchemaTypeSystemImpl && > ((SchemaTypeSystemImpl)system).isIncomplete()) > return false; > > boolean success = true; > List types = new ArrayList(); > types.addAll(Arrays.asList(system.globalTypes())); > types.addAll(Arrays.asList(system.documentTypes())); > types.addAll(Arrays.asList(system.attributeTypes())); > for (Iterator i = types.iterator(); i.hasNext(); ) > { > SchemaType type = (SchemaType)i.next(); > if (type.isBuiltinType()) > continue; > if (type.getFullJavaName() == null) > continue; > String fjn = type.getFullJavaName(); > Writer writer = null; > > ! // here we perform validation for interfaces that should extends > ! // this type. We check whether all methods in interfaces will be > ! // present or some methods will be present in supertype, in this > case > ! // this also Ok. > ! if (!((SchemaTypeImpl)type).validateMethods() ){ > ! System.err.println("Was found unimplemented methods. See above > information"); > ! return false; > ! > ! } > try > { > // Generate interface class > writer = filer.createSourceFile(fjn); > SchemaTypeCodePrinter.printType(writer, type, options); > } > catch (IOException e) > { > System.err.println("IO Error " + e); > success = false; > } > finally { > try { if (writer != null) writer.close(); } catch > (IOException e) {} > } > try > { > // Generate Implementation class > fjn = type.getFullJavaImplName(); > writer = filer.createSourceFile(fjn); > SchemaTypeCodePrinter.printTypeImpl(writer, type, options); > } > catch (IOException e) > { > System.err.println("IO Error " + e); > success = false; > } > finally { > try { if (writer != null) writer.close(); } catch > (IOException e) {} > } > } > return success; > } > This block is new in SchemaTypeImpl.java : > /** > * This method should be called instead of > <code>InterfaceExtension.validateMethods()</code> > * for validation interfaces for THIS type. > * The reason why <code>InterfaceExtension.validateMethods()</code> is > bad : > * methods from interface can be already implemented in base type. So > * we don't need to implement them . > */ > public boolean validateMethods(){ > InterfaceExtension[] extension = getInterfaceExtensions(); > for (int i = 0; i < extension.length; i++) { > if ( !validateMethods( (InterfaceExtensionImpl)extension[i])) { > return false; > } > } > return true; > } > > private boolean validateMethods(InterfaceExtensionImpl extensionImpl) { > InterfaceExtension.MethodSignature[] methods = > extensionImpl.getAbsentMethods(); > InterfaceExtension.MethodSignature[] inherited = > getAllInheritedMethods(); > for (int i = 0; i < methods.length; i++) { > InterfaceExtension.MethodSignature method = methods[i]; > > boolean flag = false; > for (int j = 0; j < inherited.length; j++) { > > if ( extensionImpl.equals( method, > inherited[j])){ > flag = true; > } > } > if ( !flag ){ > extensionImpl.error( method ); > return false; > } > } > return true; > } > > private InterfaceExtension.MethodSignature[] getAllInheritedMethods(){ > List list = new LinkedList(); > SchemaType type = getBaseType(); > while ( type!= null ){ > if (type instanceof SchemaTypeImpl) { > SchemaTypeImpl typeImpl = (SchemaTypeImpl) type; > InterfaceExtension[] extensions = > typeImpl.getInterfaceExtensions(); > if (extensions != null) { > for (int i = 0; i < extensions.length; > i++) { > > list.addAll(Arrays.asList(extensions[i].getMethods())); > } > } > } > type = type.getBaseType(); > } > > return (InterfaceExtension.MethodSignature[]) > list.toArray( new > InterfaceExtension.MethodSignature[list.size()]); > } > Changes in InterfaceExtensionImpl.java : > New attributes : > private List myNotFoundMethods = new LinkedList(); > private XmlObject myXMLObject ; > Inside method : static InterfaceExtensionImpl newInstance(JamClassLoader > loader, NameSet xbeanSet, Extensionconfig.Interface intfXO) > > result.myXMLObject = intfXO; > Changed block ( three new methods and changed old methods validateMethod() > and validateMethods(): > > public void error( MethodSignature signature){ > BindingConfigImpl.error("Handler class '" + > _delegateToClassName + "' does not contain method " + > ((MethodSignatureImpl)signature).getSignature(), > myXMLObject); > } > > /** > * This method perform "light" comparison for two methods signature > * based only on methods names and signatures. Real comperison in > * MethodSignatureImpl perform also checking for outer class name. > * @param method1 > * @param method2 > * @return > */ > public boolean equals( InterfaceExtension.MethodSignature method1 , > InterfaceExtension.MethodSignature method2 ){ > > return ( (MethodSignatureImpl)method1).lightEqual( method2 ); > } > > /** > * Changed - will always return true. > * This is incorrect place for determining correctness of interface. > * Validation logic is moved into SchemaTypeImpl.validateMethods() > * @param interfaceJClass > * @param delegateJClass > * @param loc > * @return > */ > private boolean validateMethods(JClass interfaceJClass, JClass > delegateJClass, XmlObject loc) > { > //assert _delegateToClass != null : "Delegate to class handler > expected."; > boolean valid = true; > JMethod[] interfaceMethods = interfaceJClass.getMethods(); > List list = new LinkedList(); > //_methods = new MethodSignatureImpl[interfaceMethods.length]; > for (int i = 0; i < interfaceMethods.length; i++) > { > JMethod method; > try { > method = validateMethod(interfaceJClass, > delegateJClass, interfaceMethods[i], loc); > if (method != null) { > //_methods[i] = new > MethodSignatureImpl(getStaticHandler(), method); > list.add(new MethodSignatureImpl(getStaticHandler(), > method)); > } > else { > valid = false; > } > } > catch (MethodNotFoundException e) { > // we didn't find method. If method was not > found in static handler > // by name and signature - then it was placed > in myNotFoundMethods list. > // in this case validation will be performed > later. And we don't > // get this exception. But if method was > actually found in handler, > // but its return type or exceptions that it > can throws is not > // the same as declared in interface then we > got this exception > // and we should stop. > return false; > } > } > _methods = (MethodSignatureImpl[])list.toArray( new > MethodSignatureImpl[ list.size()] ); > //return valid; > return true; > } > /** > * Changed. > * Incorrect place for decision about valid method. > * Validation logic is moved into SchemaTypeImpl.validateMethods() > * @param interfaceJClass > * @param delegateJClass > * @param method > * @param loc > * @return > */ > private JMethod validateMethod(JClass interfaceJClass, JClass > delegateJClass, JMethod method, XmlObject loc) > throws MethodNotFoundException { > String methodName = method.getSimpleName(); > JParameter[] params = method.getParameters(); > JClass returnType = method.getReturnType(); > JClass[] delegateParams = new JClass[params.length+1]; > delegateParams[0] = > returnType.forName("org.apache.xmlbeans.XmlObject"); > for (int i = 1; i < delegateParams.length; i++) > { > delegateParams[i] = params[i-1].getType(); > } > JMethod handlerMethod = null; > handlerMethod = getMethod(delegateJClass, methodName, > delegateParams); > if (handlerMethod==null) > { > MethodSignatureImpl signature = new MethodSignatureImpl( "", > method); > myNotFoundMethods.add( signature ); > // BindingConfigImpl.error("Handler class '" + > delegateJClass.getQualifiedName() + "' does not contain method " + methodName > + "(" + listTypes(delegateParams) + ")", loc); > return null; > } > // check for throws exceptions > JClass[] intfExceptions = method.getExceptionTypes(); > JClass[] delegateExceptions = handlerMethod.getExceptionTypes(); > if ( delegateExceptions.length!=intfExceptions.length ) > { > BindingConfigImpl.error("Handler method '" + > delegateJClass.getQualifiedName() + "." + methodName + "(" + > listTypes(delegateParams) + > ")' must declare the same exceptions as the interface method > '" + interfaceJClass.getQualifiedName() + "." + methodName + "(" + > listTypes(params), loc); > throw new MethodNotFoundException(); > //return null; > } > for (int i = 0; i < delegateExceptions.length; i++) > { > if ( delegateExceptions[i]!=intfExceptions[i] ) > { > BindingConfigImpl.error("Handler method '" + > delegateJClass.getQualifiedName() + "." + methodName + "(" + > listTypes(delegateParams) + > ")' must declare the same exceptions as the interface > method '" + interfaceJClass.getQualifiedName() + "." + methodName + "(" + > listTypes(params), loc); > throw new MethodNotFoundException(); > //return null; > } > } > if (!handlerMethod.isPublic() || !handlerMethod.isStatic()) > { > BindingConfigImpl.error("Method '" + > delegateJClass.getQualifiedName() + "." + methodName + "(" + > listTypes(delegateParams) + ")' must be declared public and static.", loc); > throw new MethodNotFoundException(); > //return null; > } > if (!returnType.equals(handlerMethod.getReturnType())) > { > BindingConfigImpl.error("Return type for method '" + > handlerMethod.getReturnType() + " " + delegateJClass.getQualifiedName() + > "." + methodName + "(" + listTypes(delegateParams) + ")' > does not match the return type of the interface method :'" + returnType + > "'.", loc); > throw new MethodNotFoundException(); > //return null; > } > return method; > } > public InterfaceExtensionImpl.MethodSignatureImpl[] getAbsentMethods(){ > return (InterfaceExtensionImpl.MethodSignatureImpl[]) > myNotFoundMethods.toArray( > new > InterfaceExtensionImpl.MethodSignatureImpl[myNotFoundMethods.size()]); > } > > > /** > * This exception will be thrown if method was FOUND in handler > * via name and signature but it have wrong return type, exceptions that > * can be thrown , etc. > * @author ads > * > */ > private class MethodNotFoundException extends Exception{ > > } > I can also send all these changed java files . -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]