Patch https://bugs.eclipse.org/bugs/attachment.cgi?id=64528 from https://bugs.eclipse.org/bugs/show_bug.cgi?id=163890.
Major performance improvement on EL bean resolution (Matthias Fuessel) plus regression JUnits (Cameron Bateman/Oracle).
diff --git a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/.settings/org.eclipse.jdt.core.prefs b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/.settings/org.eclipse.jdt.core.prefs
index 0694208..444ca5c 100644
--- a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/.settings/org.eclipse.jdt.core.prefs
+++ b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/.settings/org.eclipse.jdt.core.prefs
@@ -1,7 +1,62 @@
-#Tue Apr 10 08:55:28 PDT 2007
+#Tue May 15 17:20:53 PDT 2007
eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=ignore
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=ignore
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.5
diff --git a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/META-INF/MANIFEST.MF b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/META-INF/MANIFEST.MF
index fe63dac..2439828 100644
--- a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/META-INF/MANIFEST.MF
+++ b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/META-INF/MANIFEST.MF
@@ -17,7 +17,8 @@
org.eclipse.emf.edit,
org.eclipse.jface.text,
org.eclipse.jst.jsf.core,
- org.eclipse.jst.jsf.common
+ org.eclipse.jst.jsf.common,
+ org.eclipse.core.resources
Eclipse-LazyStart: true
Bundle-Activator: org.eclipse.jst.jsf.context.symbol.tests.ContextSymbolTestPlugin
Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/AllTests.java b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/AllTests.java
index 64b4a27..ac67a3c 100644
--- a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/AllTests.java
+++ b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/AllTests.java
@@ -25,11 +25,12 @@
*/
public static Test suite()
{
- TestSuite suite = new TestSuite("Test for org.eclipse.jst.jsf.validation.el.tests");
+ TestSuite suite = new TestSuite("Test for base symbols framework");
//$JUnit-BEGIN$
suite.addTestSuite(TestIJavaTypeDescriptor2.class);
suite.addTestSuite(TestIPropertySymbolItemProvider.class);
suite.addTestSuite(TestTypeCoercion.class);
+ suite.addTestSuite(TestIJavaTypeDescriptor2_ChangeStability.class);
//$JUnit-END$
return suite;
}
diff --git a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/ModelBaseTestCase.java b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/ModelBaseTestCase.java
index 638292c..299cd29 100644
--- a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/ModelBaseTestCase.java
+++ b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/ModelBaseTestCase.java
@@ -19,7 +19,6 @@
import org.eclipse.jdt.core.IType;
import org.eclipse.jst.jsf.context.symbol.IBeanInstanceSymbol;
-import org.eclipse.jst.jsf.context.symbol.IBeanPropertySymbol;
import org.eclipse.jst.jsf.context.symbol.IJavaTypeDescriptor2;
import org.eclipse.jst.jsf.context.symbol.IPropertySymbol;
import org.eclipse.jst.jsf.context.symbol.SymbolFactory;
@@ -100,13 +99,17 @@
SymbolFactory.eINSTANCE.createIBeanInstanceSymbol();
bean.setTypeDescriptor(testBeanDescriptor);
bean.setName(beanClassName);
+ populatePropertyMap(bean, properties);
+ return bean;
+ }
+
+ protected void populatePropertyMap(IBeanInstanceSymbol bean, Map<String, IPropertySymbol> properties)
+ {
List<IPropertySymbol> propertyList = bean.getProperties();
for(final Iterator<IPropertySymbol> it = propertyList.iterator(); it.hasNext();)
{
final IPropertySymbol property = it.next();
properties.put(property.getName(), property);
}
-
- return bean;
}
}
diff --git a/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/TestIJavaTypeDescriptor2_ChangeStability.java b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/TestIJavaTypeDescriptor2_ChangeStability.java
new file mode 100644
index 0000000..b00e25d
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.context.symbol.tests/src/org/eclipse/jst/jsf/context/symbol/tests/TestIJavaTypeDescriptor2_ChangeStability.java
@@ -0,0 +1,536 @@
+package org.eclipse.jst.jsf.context.symbol.tests;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.Type;
+import org.eclipse.jdt.core.dom.TypeDeclaration;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jst.jsf.common.internal.types.TypeConstants;
+import org.eclipse.jst.jsf.common.util.TypeUtil;
+import org.eclipse.jst.jsf.context.symbol.IBeanInstanceSymbol;
+import org.eclipse.jst.jsf.context.symbol.IBeanMethodSymbol;
+import org.eclipse.jst.jsf.context.symbol.IJavaTypeDescriptor2;
+import org.eclipse.jst.jsf.context.symbol.IMethodSymbol;
+import org.eclipse.jst.jsf.context.symbol.IObjectSymbol;
+import org.eclipse.jst.jsf.context.symbol.IPropertySymbol;
+import org.eclipse.jst.jsf.context.symbol.ITypeDescriptor;
+import org.eclipse.jst.jsf.context.symbol.SymbolFactory;
+import org.eclipse.jst.jsf.core.tests.TestsPlugin;
+import org.eclipse.text.edits.TextEdit;
+
+
+/**
+ * Tests the java type descriptor's ability to react correctly to changes
+ * in its underlying type. This is very important when type and symbol caching
+ * are enabled.
+ *
+ * @author cbateman
+ *
+ */
+public class TestIJavaTypeDescriptor2_ChangeStability extends ModelBaseTestCase
+{
+ private IBeanInstanceSymbol _testBean1Symbol;
+ private IBeanInstanceSymbol _testBean1SubclassSymbol;
+ private IBeanInstanceSymbol _testBean2Symbol;
+ private IBeanInstanceSymbol _testBean2SubclassSymbol;
+ private IBeanInstanceSymbol _testBeanWithGenericProperties;
+
+ private Map<String, IPropertySymbol> _beanProperties;
+ private Map<String, IBeanMethodSymbol> _bean1Methods;
+ private Map<String, IPropertySymbol> _beanSubclassProperties;
+ private Map<String, IBeanMethodSymbol> _bean2Methods;
+ private Map<String, IPropertySymbol> _bean2Properties;
+ private Map<String, IBeanMethodSymbol> _beanMethodsSubclass;
+ private Map<String, IPropertySymbol> _genericProperties;
+
+ private final static String packageName1 = "com.test";
+ private final static String testBeanName1 = "TestBean1";
+ private final static String testBean1Sig = "L"+packageName1+"."+testBeanName1+";";
+ private final static String testBeanSubclass1 = "TestBean1Subclass";
+ private final static String testBeanName2 = "TestBean2";
+ private final static String testBean2Subclass = "TestBean2Subclass";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ // load ITestBean2 first due to later dependencies
+ loadSourceClass(ContextSymbolTestPlugin.getDefault().getBundle(), "/testdata/ITestBean2.java.data", packageName1, "ITestBean2");
+
+ // load another bean first since others have a dependency on on it
+ loadSourceClass(TestsPlugin.getDefault().getBundle(), "/testfiles/AnotherBean.java.data", packageName1, "AnotherBean");
+ assertNotNull(_jdtTestEnvironment.getJavaProject().findType(packageName1+"."+"AnotherBean"));
+
+ _beanProperties = new HashMap<String, IPropertySymbol>();
+ _testBean1Symbol =
+ setupBeanProperty(TestsPlugin.getDefault().getBundle(),
+ "/testfiles/TestBean1.java.data", packageName1,
+ testBeanName1, _beanProperties);
+ _bean1Methods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(_bean1Methods, _testBean1Symbol);
+
+ _beanSubclassProperties = new HashMap<String, IPropertySymbol>();
+ _testBean1SubclassSymbol =
+ setupBeanProperty(TestsPlugin.getDefault().getBundle(),
+ "/testfiles/TestBean1Subclass.java.data", packageName1,
+ testBeanSubclass1, _beanSubclassProperties);
+
+ _genericProperties = new HashMap<String, IPropertySymbol>();
+
+ _testBeanWithGenericProperties =
+ setupBeanProperty(ContextSymbolTestPlugin.getDefault().getBundle(),
+ "/testdata/TestBeanWithGenericProperties.java.data", packageName1,
+ "TestBeanWithGenericProperties",_genericProperties);
+
+ _bean2Methods = new HashMap<String, IBeanMethodSymbol>();
+ _testBean2Symbol =
+ setupBeanMethods("/testdata/TestBean2.java.data", testBeanName2, _bean2Methods);
+ _bean2Properties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean2Symbol, _bean2Properties);
+
+ _beanMethodsSubclass = new HashMap<String, IBeanMethodSymbol>();
+ _testBean2SubclassSymbol =
+ setupBeanMethods("/testdata/TestBean2Subclass.java.data", testBean2Subclass, _beanMethodsSubclass);
+ }
+
+
+ private IBeanInstanceSymbol setupBeanMethods(String fileName, String beanClassName, Map<String, IBeanMethodSymbol> methods) throws Exception
+ {
+ loadSourceClass(ContextSymbolTestPlugin.getDefault().getBundle(), fileName, packageName1, beanClassName);
+
+ final IType testBean1Type =
+ _jdtTestEnvironment.getJavaProject().findType(packageName1+"."+beanClassName);
+ assertNotNull(testBean1Type);
+
+ final IJavaTypeDescriptor2 testBeanDescriptor =
+ SymbolFactory.eINSTANCE.createIJavaTypeDescriptor2();
+ testBeanDescriptor.setType(testBean1Type);
+
+ IBeanInstanceSymbol bean =
+ SymbolFactory.eINSTANCE.createIBeanInstanceSymbol();
+ bean.setTypeDescriptor(testBeanDescriptor);
+ bean.setName(beanClassName);
+ populateMethodMap(methods, bean);
+ return bean;
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ _jdtTestEnvironment.getProjectEnvironment().getTestProject().delete(true, null);
+ }
+
+ private final static String NON_BEAN_METHOD_CONTENTS = "public String myActionSource(){return \"foo\";}";
+ private final static String NON_BEAN_METHOD_SIG = Signature.createMethodSignature(new String[0], TypeConstants.TYPE_STRING);
+ /**
+ * Check the affect of adding a non-bean (not a getter/setter match) on
+ * the IJavaTypeDescriptor2
+ */
+ public void testAddNonBeanMethod() throws Exception
+ {
+ // pre-cond => basic setup
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ IMethod newMethod = type.createMethod(NON_BEAN_METHOD_CONTENTS, null, true, null);
+ assertNotNull(newMethod);
+ assertEquals(NON_BEAN_METHOD_SIG, TypeUtil.resolveMethodSignature(type, newMethod.getSignature()));
+ assertTrue(newMethod.exists());
+
+ // post-cond: bean has new method
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ assertEquals(_bean1Methods.size()+1, newMethods.size());
+ // should be the same if we remove the new method
+ assertNotNull(newMethods.remove("myActionSource"));
+ compareMethodMaps(_bean1Methods, newMethods);
+
+ // post-cond: properties are unchanged
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ compareSymbolMaps(_beanProperties, newProperties);
+ }
+
+ public void testRemoveNonBeanMethod() throws Exception
+ {
+ // pre-cond => basic setup, delete a non-bean method
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ IMethod method = type.getMethod("get", new String[0]);
+ assertNotNull(method);
+ method.delete(true, null);
+ assertFalse(method.exists());
+
+ // post-cond: bean has one less method
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ assertEquals(_bean1Methods.size()-1, newMethods.size());
+ assertTrue(newMethods.get("get") == null);
+ // should be the same if we remove the method from expected
+ assertNotNull(_bean1Methods.remove("get"));
+ compareMethodMaps(_bean1Methods, newMethods);
+
+ // post-cond: properties are unchanged
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ compareSymbolMaps(_beanProperties, newProperties);
+ }
+
+ private final static String BEAN_PROPERTY_NAME = "anAddedStringProperty";
+ private final static String BEAN_METHOD_NAME = "getAnAddedStringProperty";
+ private final static String BEAN_METHOD_CONTENTS =
+ "public String "+BEAN_METHOD_NAME+"() {return \"foo\";}";
+ private final static String BEAN_METHOD_SIG =
+ Signature.createMethodSignature(new String[0], TypeConstants.TYPE_STRING);
+
+ public void testAddBeanMethod() throws Exception
+ {
+ // pre-cond => basic setup
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ IMethod newMethod = type.createMethod(BEAN_METHOD_CONTENTS, null, true, null);
+ assertNotNull(newMethod);
+ assertTrue(newMethod.exists());
+ assertEquals(BEAN_METHOD_SIG, TypeUtil.resolveMethodSignature(type, newMethod.getSignature()));
+
+ {
+ // post-cond: bean has new method
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ assertEquals(_bean1Methods.size()+1, newMethods.size());
+ // should be the same if we remove the new method
+ assertNotNull(newMethods.remove(BEAN_METHOD_NAME));
+ compareMethodMaps(_bean1Methods, newMethods);
+ }
+
+ {
+ // post-cond: bean has a new property
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ assertEquals(_beanProperties.size()+1, newProperties.size());
+ // should be the same if we remove the new property
+ IPropertySymbol prop = newProperties.remove(BEAN_PROPERTY_NAME);
+ assertEquals(TypeConstants.TYPE_STRING, prop.getTypeDescriptor().getTypeSignature());
+ compareSymbolMaps(_beanProperties, newProperties);
+ }
+ }
+
+ private final static String EXISTING_BEAN_PROPERTY_TO_REMOVE = "readonlyStringProperty";
+ private final static String EXISTING_BEAN_METHOD = "getReadonlyStringProperty";
+ private final static String EXISTING_BEAN_METHOD_SIG = BEAN_METHOD_SIG;
+
+ public void testRemoveBeanMethod() throws Exception
+ {
+ // pre-cond => basic setup, delete a non-bean method
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ IMethod method = type.getMethod(EXISTING_BEAN_METHOD, new String[0]);
+ assertNotNull(method);
+ assertEquals(EXISTING_BEAN_METHOD_SIG, TypeUtil.resolveMethodSignature(type, method.getSignature()));
+ assertTrue(method.exists());
+ method.delete(true, null);
+ assertFalse(method.exists());
+
+ // post-cond: bean has one less method
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ assertEquals(_bean1Methods.size()-1, newMethods.size());
+ assertTrue(newMethods.get(EXISTING_BEAN_METHOD) == null);
+ // should be the same if we remove the method from expected
+ assertNotNull(_bean1Methods.remove(EXISTING_BEAN_METHOD));
+ compareMethodMaps(_bean1Methods, newMethods);
+
+ // post-cond: bean has one less property
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ assertEquals(_beanProperties.size()-1, newProperties.size());
+ // should be the same if we remove the same property from the expected
+ IPropertySymbol prop = _beanProperties.remove(EXISTING_BEAN_PROPERTY_TO_REMOVE);
+ assertEquals(TypeConstants.TYPE_STRING, prop.getTypeDescriptor().getTypeSignature());
+ compareSymbolMaps(_beanProperties, newProperties);
+ }
+
+ // NOTE: it is ADifferentReadonlyPropertyName with a capital "A" because it is followed
+ // by a capital letter (D), which by bean rules means don't lower-cap the property name
+ private final static String NEW_READONLY_BEAN_PROP_NAME = "ADifferentReadonlyPropertyName";
+ private final static String NEW_READONLY_BEAN_METHOD_NAME = "getADifferentReadonlyPropertyName";
+
+ public void testRenameBeanProperty() throws Exception
+ {
+ // pre-cond => basic setup, delete a non-bean method
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ IMethod method = type.getMethod(EXISTING_BEAN_METHOD, new String[0]);
+ assertNotNull(method);
+ assertEquals(EXISTING_BEAN_METHOD_SIG, TypeUtil.resolveMethodSignature(type, method.getSignature()));
+ assertTrue(method.exists());
+ method.rename(NEW_READONLY_BEAN_METHOD_NAME, false, null);
+ method = type.getMethod(NEW_READONLY_BEAN_METHOD_NAME, new String[0]);
+ assertTrue(method.exists());
+
+ // post-cond: bean has same number of methods
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ assertEquals(_bean1Methods.size(), newMethods.size());
+ assertTrue(newMethods.get(EXISTING_BEAN_METHOD) == null);
+ // should be the same if we remove existing and add new one from newMethods
+ assertNotNull(_bean1Methods.remove(EXISTING_BEAN_METHOD));
+ IBeanMethodSymbol changedMethod = newMethods.get(NEW_READONLY_BEAN_METHOD_NAME);
+ assertEquals(BEAN_METHOD_SIG, changedMethod.getSignature());
+ _bean1Methods.put(NEW_READONLY_BEAN_METHOD_NAME, changedMethod);
+ compareMethodMaps(_bean1Methods, newMethods);
+
+ // post-cond: bean has same number of properties
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ assertEquals(_beanProperties.size(), newProperties.size());
+ // should be the same if we replace with the new property
+ IPropertySymbol prop = newProperties.get(NEW_READONLY_BEAN_PROP_NAME);
+ assertNotNull(prop);
+ assertEquals(TypeConstants.TYPE_STRING, prop.getTypeDescriptor().getTypeSignature());
+ assertNotNull(_beanProperties.remove(EXISTING_BEAN_PROPERTY_TO_REMOVE));
+ _beanProperties.put(prop.getName(), prop);
+ compareSymbolMaps(_beanProperties, newProperties);
+ }
+
+ private static final String READONLY_BEAN_REPLACEMENT_METHOD =
+ "public Integer "+EXISTING_BEAN_METHOD+"(){return new Integer(4);}";
+ private static final String READONLY_BEAN_REPLACEMENT_SIG =
+ Signature.createMethodSignature(new String[0], TypeConstants.TYPE_BOXED_INTEGER);
+
+ public void testChangeTypeOfGetter() throws Exception
+ {
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ IMethod method = type.getMethod(EXISTING_BEAN_METHOD, new String[0]);
+ assertNotNull(method);
+ assertTrue(method.exists());
+
+ // remove old, add new
+ method.delete(true, null);
+ assertFalse(method.exists());
+ type.createMethod(READONLY_BEAN_REPLACEMENT_METHOD, null, true, null);
+ assertTrue(method.exists());
+
+ // post-cond: bean has the same number of methods
+ // but, we need to replace the changed one in _bean1Methods
+ // for the maps to equal
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ assertEquals(_bean1Methods.size(), newMethods.size());
+ assertNotNull(newMethods.get(EXISTING_BEAN_METHOD));
+ IBeanMethodSymbol methodSymbol = _bean1Methods.remove(EXISTING_BEAN_METHOD);
+ assertNotNull(methodSymbol);
+ assertEquals(EXISTING_BEAN_METHOD_SIG, methodSymbol.getSignature());
+ // should be the same if we swap the new method into the old map
+ methodSymbol = newMethods.get(EXISTING_BEAN_METHOD);
+ assertNotNull(methodSymbol);
+ assertEquals(READONLY_BEAN_REPLACEMENT_SIG, methodSymbol.getSignature());
+ _bean1Methods.put(EXISTING_BEAN_METHOD, methodSymbol);
+ compareMethodMaps(_bean1Methods, newMethods);
+
+ // post-cond: bean's type signature has changed
+ // post-cond: same number of props
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ assertEquals(_beanProperties.size(), newProperties.size());
+ // should be the same if we replace the same property from the expected
+ IPropertySymbol prop = _beanProperties.remove(EXISTING_BEAN_PROPERTY_TO_REMOVE);
+ assertEquals(TypeConstants.TYPE_STRING, prop.getTypeDescriptor().getTypeSignature());
+ prop = newProperties.get(EXISTING_BEAN_PROPERTY_TO_REMOVE);
+ assertEquals(TypeConstants.TYPE_BOXED_INTEGER, prop.getTypeDescriptor().getTypeSignature());
+ _beanProperties.put(EXISTING_BEAN_PROPERTY_TO_REMOVE, prop);
+ compareSymbolMaps(_beanProperties, newProperties);
+ }
+
+ private final static String WRITEONLY_BEAN_PROPERTY_NAME =
+ "writeonlyStringProperty";
+ private final static String WRITEONLY_BEAN_REPLACEMENT_METHOD_NAME =
+ "setWriteonlyStringProperty";
+ private final static String WRITEONLY_BEAN_REPLACMENT_CONTENTS =
+ "public void "+WRITEONLY_BEAN_REPLACEMENT_METHOD_NAME
+ +"(Integer newValue){}";
+ private final static String EXISTING_BEAN_SETTER_METHOD_SIG =
+ Signature.createMethodSignature(new String[] {TypeConstants.TYPE_STRING}, Signature.SIG_VOID);
+ private final static String REPLACEMENT_BEAN_SETTER_METHOD_SIG =
+ Signature.createMethodSignature(new String[] {TypeConstants.TYPE_BOXED_INTEGER}, Signature.SIG_VOID);
+
+ public void testChangeTypeOfSetter() throws Exception
+ {
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ IMethod method = type.getMethod(WRITEONLY_BEAN_REPLACEMENT_METHOD_NAME, new String[]{"QString;"});
+ assertNotNull(method);
+ assertTrue(method.exists());
+
+ // remove old, add new
+ method.delete(true, null);
+ assertFalse(method.exists());
+ method = type.createMethod(WRITEONLY_BEAN_REPLACMENT_CONTENTS, null, true, null);
+ assertTrue(method.exists());
+
+ // post-cond: bean has the same number of methods
+ // but, we need to replace the changed one in _bean1Methods
+ // for the maps to equal
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ assertEquals(_bean1Methods.size(), newMethods.size());
+ assertNotNull(newMethods.get(WRITEONLY_BEAN_REPLACEMENT_METHOD_NAME));
+ IBeanMethodSymbol methodSymbol =
+ _bean1Methods.remove(WRITEONLY_BEAN_REPLACEMENT_METHOD_NAME);
+ assertNotNull(methodSymbol);
+ assertEquals(EXISTING_BEAN_SETTER_METHOD_SIG, methodSymbol.getSignature());
+ // should be the same if we swap the new method into the old map
+ methodSymbol = newMethods.get(WRITEONLY_BEAN_REPLACEMENT_METHOD_NAME);
+ assertNotNull(methodSymbol);
+ assertEquals(REPLACEMENT_BEAN_SETTER_METHOD_SIG, methodSymbol.getSignature());
+ _bean1Methods.put(WRITEONLY_BEAN_REPLACEMENT_METHOD_NAME, methodSymbol);
+ compareMethodMaps(_bean1Methods, newMethods);
+
+ // post-cond: bean's type signature has changed
+ // post-cond: same number of props
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ assertEquals(_beanProperties.size(), newProperties.size());
+ // should be the same if we replace the same property from the expected
+ IPropertySymbol prop = _beanProperties.remove(WRITEONLY_BEAN_PROPERTY_NAME);
+ assertEquals(TypeConstants.TYPE_STRING, prop.getTypeDescriptor().getTypeSignature());
+ prop = newProperties.get(WRITEONLY_BEAN_PROPERTY_NAME);
+ assertEquals(TypeConstants.TYPE_BOXED_INTEGER, prop.getTypeDescriptor().getTypeSignature());
+ _beanProperties.put(WRITEONLY_BEAN_PROPERTY_NAME, prop);
+ compareSymbolMaps(_beanProperties, newProperties);
+ }
+
+ public void testAddSuperType() throws Exception
+ {
+ IType type = _testBean1Symbol.getJavaTypeDescriptor().getType();
+ changeSuperType(type, _testBean2Symbol.getJavaTypeDescriptor().getType());
+
+ // post-cond: bean has the same number of methods
+ // but, we need to replace the changed one in _bean1Methods
+ // for the maps to equal
+ Map<String, IBeanMethodSymbol> newMethods = new HashMap<String, IBeanMethodSymbol>();
+ populateMethodMap(newMethods,_testBean1Symbol);
+ Map<String, IBeanMethodSymbol> mergedMethodMap = new HashMap<String, IBeanMethodSymbol>();
+ mergedMethodMap.putAll(_bean1Methods);
+ mergedMethodMap.putAll(_bean2Methods);
+
+ assertEquals(mergedMethodMap.size(), newMethods.size());
+ compareMethodMaps(mergedMethodMap, newMethods);
+
+ // post-cond: bean's type signature has changed
+ // post-cond: same number of props
+ Map<String, IPropertySymbol> newProperties = new HashMap<String, IPropertySymbol>();
+ populatePropertyMap(_testBean1Symbol, newProperties);
+ // should be the same if we merge the two expected maps
+ Map<String, IPropertySymbol> mergedSymbolMap = new HashMap<String, IPropertySymbol>();
+ mergedSymbolMap.putAll(_beanProperties);
+ mergedSymbolMap.putAll(_bean2Properties);
+ // bean 2 has a single bean property
+ assertEquals(mergedSymbolMap.size(), newProperties.size());
+ compareSymbolMaps(mergedSymbolMap, newProperties);
+ }
+
+ private void populateMethodMap(Map<String, IBeanMethodSymbol> methods, IBeanInstanceSymbol bean)
+ {
+ List methodList = bean.getMethods();
+ for(final Iterator it = methodList.iterator(); it.hasNext();)
+ {
+ final IBeanMethodSymbol method = (IBeanMethodSymbol) it.next();
+ methods.put(method.getName(), method);
+ }
+ }
+
+ private void compareSymbolMaps(Map<String, ? extends IObjectSymbol> expected, Map<String, ? extends IObjectSymbol> actual)
+ {
+ assertEquals(expected.size(), actual.size());
+
+ for (String name : actual.keySet())
+ {
+ ITypeDescriptor expectedTypeDesc = expected.get(name).getTypeDescriptor();
+ ITypeDescriptor actualTypeDesc = actual.get(name).getTypeDescriptor();
+
+ assertTypeDescriptorsSame(expectedTypeDesc, actualTypeDesc);
+ }
+ }
+
+ private void compareMethodMaps(Map<String, ? extends IMethodSymbol> expected, Map<String, ? extends IMethodSymbol> actual)
+ {
+ assertEquals(expected.size(), actual.size());
+
+ for (String name : actual.keySet())
+ {
+ assertEquals(expected.get(name).getSignature(), actual.get(name).getSignature());
+ }
+ }
+
+ private void assertTypeDescriptorsSame(ITypeDescriptor expectedTypeDesc, ITypeDescriptor actualTypeDesc)
+ {
+ assertEquals(expectedTypeDesc.getTypeSignature()
+ , actualTypeDesc.getTypeSignature());
+ if (expectedTypeDesc.getArrayElement() != null)
+ {
+ assertNotNull(actualTypeDesc.getArrayElement());
+ assertTypeDescriptorsSame(expectedTypeDesc.getArrayElement().getTypeDescriptor()
+ , actualTypeDesc.getArrayElement().getTypeDescriptor());
+ }
+ else
+ {
+ assertNull(actualTypeDesc.getArrayElement());
+ }
+
+ assertEquals(expectedTypeDesc.getInterfaceTypeSignatures()
+ , actualTypeDesc.getInterfaceTypeSignatures());
+ assertEquals(expectedTypeDesc.getSuperTypeSignatures()
+ , actualTypeDesc.getSuperTypeSignatures());
+ assertEquals(expectedTypeDesc.getTypeParameterSignatures()
+ , actualTypeDesc.getTypeParameterSignatures());
+ }
+
+ private void changeSuperType(IType type, IType newSuperType) throws Exception
+ {
+ ICompilationUnit cu = type.getCompilationUnit().getWorkingCopy(null);
+ CompilationUnit astRoot = createASTAndStartRecording(cu);
+
+ // modify the AST
+ TypeDeclaration typeDeclaration = (TypeDeclaration)astRoot.types().get(0);
+ AST ast = typeDeclaration.getAST();
+ Name superName = ast.newName(newSuperType.getFullyQualifiedName());
+ Type superType = ast.newSimpleType(superName);
+ typeDeclaration.setSuperclassType(superType);
+
+ commitAST(cu, astRoot);
+ }
+
+ private CompilationUnit createASTAndStartRecording(ICompilationUnit cu) throws Exception
+ {
+ // creation of DOM/AST from a ICompilationUnit
+ ASTParser parser = ASTParser.newParser(AST.JLS3);
+ parser.setSource(cu);
+ // start record of the modifications
+ CompilationUnit astRoot = (CompilationUnit) parser.createAST(null);
+ astRoot.recordModifications();
+ return astRoot;
+ }
+
+ private void commitAST(ICompilationUnit cu, CompilationUnit astRoot) throws Exception
+ {
+ String source = cu.getBuffer().getContents();
+ Document document= new Document(source);
+
+ // computation of the text edits
+ TextEdit edits = astRoot.rewrite(document, cu.getJavaProject().getOptions(true));
+
+ // computation of the new source code
+ edits.apply(document);
+ String newSource = document.get();
+
+ // update of the compilation unit
+ cu.getBuffer().setContents(newSource);
+ cu.commitWorkingCopy(true, null);
+ }
+}