[ 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]

Reply via email to