[prev in list] [next in list] [prev in thread] [next in thread] 

List:       xmlbeans-dev
Subject:    [jira] Updated: (XMLBEANS-207) Big issue with bad validation of interfaces when .xsdconfig file is u
From:       "Denis Anisimov (JIRA)" <xmlbeans-dev () xml ! apache ! org>
Date:       2005-09-26 13:51:05
Message-ID: 246974971.1127742665872.JavaMail.jira () ajax ! apache ! org
[Download RAW message or body]

     [ http://issues.apache.org/jira/browse/XMLBEANS-207?page=all ]

Denis Anisimov updated XMLBEANS-207:
------------------------------------

    Attachment: InterfaceExtensionImpl.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: dev-unsubscribe@xmlbeans.apache.org
For additional commands, e-mail: dev-help@xmlbeans.apache.org


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic