Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 358568

Summary: TemplateContext.primGetMethod returns the wrong method
Product: z_Archived Reporter: Joseph Vincens <jvincens>
Component: EDTAssignee: Project Inbox <edt.genframework-inbox>
Status: CLOSED FIXED QA Contact:
Severity: normal    
Priority: P1 CC: chenzhh, jeffdouglas, joepluta, jqian, mheitz, pharmon, svihovec, tww
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: All   
Whiteboard:

Description Joseph Vincens CLA 2011-09-22 08:40:39 EDT
I ran into a problem with a new workspace, SQL stopped generating. I debugged and found that TemplateContext.primGetMethod was returning the wrong method. It should be returning SqlGetByKeyStatementTemplate.genStatementBody, but was returning SqlActionStatementTemplate.genStatementBody. 

I inspected templateClass.getMethods() and it was returning the super class methods before the class ie SqlActionStatementTemplate methods before SqlGetByKeyStatementTemplate. 

I looked at the workspace and saw it was using IBM v6 jre, my old workspace was using The Sun JRE. I switched to the SUN jre and the order was different, the super methods were after the class methods.

In reading the Java docs and doing a google search I think we have a serious design flaw. The docs say "Returns an array containing Method objects reflecting all the public member methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from superclasses and superinterfaces. Array classes return all the (public) member methods inherited from the Object class. The elements in the array returned are not sorted and are not in any particular order.". The last sentence is the flaw: methods are returned in no specific order and our code relies on finding the class method before the super method.

From posts that I read in my google search (order returned by Java Class.getMethods) some people claim that if you recompile a class they have seen the order change.
Comment 1 Joseph Vincens CLA 2011-09-22 08:57:45 EDT
The fix might be easy, change the method to use getDeclaredMethods and explicitly loop on the super types. Maybe:

	do{
		for (Method m : templateClass.getDeclaredMethods()) {
			if(Modifier.isPublic(m.getModifiers())){
			......existing code starting after the for (Method m...
			}
	}while(method == null && (templateClass = templateClass.getSuperclass()) != null );
Comment 2 Matt Heitz CLA 2011-09-22 16:21:28 EDT
There's still a problem.  The parameter-matching code doesn't take overloading into account.  Say the class has two methods with the specified name.  One takes an Object (I'll call this method A) and the other takes a String (method B).  If the argument is a String, we should choose B, but if we happen to examine A first we'll choose it instead.

A solution can be written based on code from RBD's JavaLib implementation, com.ibm.etools.egl.java\egljava\egl\java\JavaLib_Lib.java  It has already been through the Java Runtime CQ.  See the method called findMethod in JavaLib_Lib.  egl.java.ArgInfo contains a lot of the useful code too.

The JavaLib code needs to be updated because it was written before Java got autoboxing.  ArgInfo has comments like "Primitives can't be converted to objects" and parts of its code are based on that assumption.

For bonus points, make it work with a varargs parameter too.
Comment 3 Matt Heitz CLA 2011-09-28 15:28:17 EDT
*** Bug 358084 has been marked as a duplicate of this bug. ***
Comment 4 Jeff Douglas CLA 2011-10-01 09:47:38 EDT
Tim and Paul (with some help from Joe) need to fix this.
Comment 5 Jeff Douglas CLA 2011-10-03 13:21:19 EDT
fixed. We used Joe's suggestion.
Comment 6 Jeff Douglas CLA 2011-10-03 13:25:19 EDT
Reopening to address Matt's question, for future.
Comment 7 Jeff Douglas CLA 2011-10-03 13:26:02 EDT
current fix does not handle method overloading
Comment 8 Brian Svihovec CLA 2011-11-14 09:51:39 EST
setting this to 1.0, as it seems any fix in this area could be too risky for the impending .7 release.  If anyone disagrees, please mention it here.
Comment 9 Matt Heitz CLA 2011-11-14 10:42:55 EST
I agree that it should be deferred.  Would be good to tackle this one early in the 1.0 cycle or we're likely to keep putting it off.
Comment 10 Matt Heitz CLA 2012-02-17 10:13:20 EST
I found another case where this is causing problems.  I'm using a development environment, with all plugins checked out and current.  (In case you're reading this a while from now, we're just about to declare 0.8 M2.)

I'm generating annotatedTest.egl from project org.eclipse.edt.tests.sql, from the kan-cvs-save server.  Function insertRowWithExecuteStatement contains an execute statement.  Its using clause includes variable row.nullableCol.  As the name implies, it's nullable.

We check for nullability in method genSetColumnValue of org.eclipse.edt.gen.java.templates.eglx.persistence\src\org\eclipse\edt\gen\java\templates\eglx\persistence\sql\SqlActionStatementTemplate.java, at line 366.  Here's the code:
	protected void genSetColumnValue(SqlActionStatement stmt, Expression expr, String stmt_or_resultSet_var, int columnIndex, Context ctx, TabbedWriter out) {
		EGLClass type = (EGLClass)expr.getType().getClassifier();
		Boolean isNullable = (Boolean)ctx.invoke("isNullable", stmt, ctx, expr);
		if(isNullable != null && isNullable){

When I run EDT in my IBM JRE, the isNullable variable is true.  That's correct.  But when I use my Sun JRE, isNullable is false.  The IRs for the record and statement look the same in both cases.

Here's the output of java -version from my Sun JRE:
java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) Client VM (build 20.5-b03, mixed mode, sharing)

Here's the output of java -version from my IBM JRE:
java version "1.6.0"
Java(TM) SE Runtime Environment (build pwi3260sr9fp1-20110208_03(SR9 FP1))
IBM J9 VM (build 2.4, JRE 1.6.0 IBM J9 2.4 Windows XP x86-32 jvmwi3260sr9-201102
03_74623 (JIT enabled, AOT enabled)
J9VM - 20110203_074623
JIT  - r9_20101028_17488ifx3
GC   - 20101027_AA)
JCL  - 20110203_01
Comment 11 Matt Heitz CLA 2012-02-24 09:47:38 EST
Oracle's "Java SE 7 and JDK 7 Compatibility" page at http://www.oracle.com/technetwork/java/javase/compatibility-417013.html mentions a change that may affect us if we switch from one JRE to another.


Area: HotSpot
Synopsis: Order of Methods returned by Class.get Methods can Vary
Description: In JDK 7, build 129, the following reflective operations in java.lang.Class changed the fixed order in which they return the methods and constructors of a class:

    getMethods
    getDeclaredMethods
    getDeclaredConstructors

This may cause issues for code that assumes (contrary to the specification) a particular order for methods or constructors.
RFE: 7023180
Comment 12 Lisa Lasher CLA 2012-04-05 13:51:27 EDT
lowering to normal severity, as the scope of the problem is limited.
Comment 13 Joseph Vincens CLA 2012-04-05 14:16:38 EDT
I raised the severity because this is happening in at least SQL, IBMi, dedicated service invocation, and Tim is seeing this in a new generator that he is working on. I've seen 2 forum entries that I would attribute to this problem. It doesn't not happen consistently so it makes the product seem unstable. We need to address this in the next release.
Comment 14 Joseph Vincens CLA 2012-04-12 08:22:39 EDT
fixed.
see org.eclipse.edt.mof/src/org/eclipse/edt/mof/codegen/api/TemplateContext.java for the change.
Look at the current class and determine if a method is parameter assignable from the arguments. If there is more than 1 method determine the most specific by comparing the methods on the current class to find the most specific. If no method is found look at the super class's methods.
Comment 15 Joseph Vincens CLA 2012-06-08 11:46:15 EDT
verified