[ 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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]