[prev in list] [next in list] [prev in thread] [next in thread]
List: xmlbeans-dev
Subject: [jira] Created: (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:48:51
Message-ID: 1222724383.1127742531092.JavaMail.jira () ajax ! apache ! org
[Download RAW message or body]
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
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