### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.ui.tests Index: ui/org/eclipse/jdt/ui/tests/core/source/GenerateToStringTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GenerateToStringTest.java,v retrieving revision 1.1 diff -u -r1.1 GenerateToStringTest.java --- ui/org/eclipse/jdt/ui/tests/core/source/GenerateToStringTest.java 9 Mar 2009 19:20:21 -0000 1.1 +++ ui/org/eclipse/jdt/ui/tests/core/source/GenerateToStringTest.java 17 Apr 2009 14:18:12 -0000 @@ -7,6 +7,7 @@ * * Contributors: * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 + * Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 *******************************************************************************/ package org.eclipse.jdt.ui.tests.core.source; @@ -22,6 +23,7 @@ import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; @@ -33,6 +35,7 @@ import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.GenerateToStringOperation; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringGenerationSettings; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringTemplateParser; +import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringGenerationSettings.CustomBuilderSettings; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; @@ -71,6 +74,26 @@ fSettings2.useBlocks= true; fSettings2.is50orHigher= true; fSettings2.is60orHigher= true; + fSettings2.customBuilderSettings= new CustomBuilderSettings(); + fSettings2.customBuilderSettings.className= "com.pack.ToStringBuilder"; + fSettings2.customBuilderSettings.label= "builder"; + fSettings2.customBuilderSettings.appendMethod= "append"; + fSettings2.customBuilderSettings.resultMethod= "toString"; + fSettings2.customBuilderSettings.chainCalls= false; + + IPackageFragment packageFragment= fRoot.createPackageFragment("com.pack", true, null); + ICompilationUnit compilationUnit= packageFragment.getCompilationUnit("ToStringBuilder.java"); + compilationUnit + .createType( + "package com.pack;\npublic class ToStringBuilder {\npublic ToStringBuilder(Object o){\n}\npublic ToStringBuilder append(String s, Object o){\nreturn null;\n}\npublic String toString(){\nreturn null;\n}\n}\n", + null, true, null); + + packageFragment= fRoot.createPackageFragment("org.another.pack", true, null); + compilationUnit= packageFragment.getCompilationUnit("AnotherToStringCreator.java"); + compilationUnit + .createType( + "package org.another.pack;\npublic class AnotherToStringCreator {\npublic AnotherToStringCreator(java.lang.Object o) {\n}\npublic AnotherToStringCreator addSth(Object o, String s) {\n return null;\n}\npublic String addSth(String s, int i){\nreturn null;\n}\npublic void addSth(boolean b, String s){\n}\npublic String getResult(){\nreturn null;\n}\n}\n", + null, true, null); } public void runOperation(IType type, IMember[] members, IJavaElement insertBefore) throws CoreException { @@ -2136,11 +2159,11 @@ } /** - * Apache ToStringbuilder - basic case + * Custom ToString() builder - basic case * * @throws Exception */ - public void testApacheBuilder() throws Exception { + public void testCustomBuilder() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" @@ -2150,7 +2173,7 @@ fSettings2.toStringStyle= 4; runOperation(a.getType("A"), members, null); - String expected= "package p;\r\n" + "\r\n" + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + String expected= "package p;\r\n" + "\r\n" + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + " @Override\r\n" + " public String toString() {\r\n" + " ToStringBuilder builder = new ToStringBuilder(this);\r\n" + " builder.append(\"aStringMethod()\", aStringMethod());\r\n" @@ -2161,11 +2184,11 @@ } /** - * Apache ToStringbuilder - skip nulls + * Custom ToString() builder - skip nulls * * @throws Exception */ - public void testApacheBuilderNulls() throws Exception { + public void testCustomBuilderNulls() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" @@ -2176,7 +2199,7 @@ fSettings2.toStringStyle= 4; runOperation(a.getType("A"), members, null); - String expected= "package p;\r\n" + "\r\n" + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + String expected= "package p;\r\n" + "\r\n" + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + " @Override\r\n" + " public String toString() {\r\n" + " ToStringBuilder builder = new ToStringBuilder(this);\r\n" + " if (aStringMethod() != null) {\r\n" + " builder.append(\"aStringMethod()\", aStringMethod());\r\n" + " }\r\n" @@ -2188,11 +2211,11 @@ } /** - * Apache ToStringbuilder - custom array toString without limit of elements + * Custom ToString() builder - custom array toString without limit of elements * * @throws Exception */ - public void testApacheBuilderArray() throws Exception { + public void testCustomBuilderArray() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] anArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " java.util.List list;\r\n" + "\r\n" + "}\r\n" + "", true, null); @@ -2202,7 +2225,7 @@ fSettings2.toStringStyle= 4; runOperation(a.getType("A"), members, null); - String expected= "package p;\r\n" + "\r\n" + "import java.util.Arrays;\r\n" + "\r\n" + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + String expected= "package p;\r\n" + "\r\n" + "import java.util.Arrays;\r\n" + "\r\n" + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] anArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " java.util.List list;\r\n" + " @Override\r\n" + " public String toString() {\r\n" + " ToStringBuilder builder = new ToStringBuilder(this);\r\n" + " builder.append(\"AArray\", Arrays.toString(AArray));\r\n" + " builder.append(\"aBool\", aBool);\r\n" @@ -2214,11 +2237,11 @@ } /** - * Apache ToStringbuilder - limit of elements but not arrays + * Custom ToString() builder - limit of elements but not arrays * * @throws Exception */ - public void testApacheBuilderLimit() throws Exception { + public void testCustomBuilderLimit() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" @@ -2232,7 +2255,7 @@ runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.Iterator;\r\n" + "import java.util.List;\r\n" + "\r\n" - + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" + " return null;\r\n" + " }\r\n" + " List list;\r\n" + " HashMap hashMap;\r\n" + " Collection wildCollection;\r\n" + " Collection integerCollection;\r\n" + " @Override\r\n" + " public String toString() {\r\n" + " final int maxLen = 10;\r\n" @@ -2252,11 +2275,11 @@ /** - * Apache ToStringbuilder - custom array toString and limit of elements + * Custom ToString() builder - custom array toString and limit of elements * * @throws Exception */ - public void testApacheBuilderArrayLimit() throws Exception { + public void testCustomBuilderArrayLimit() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" @@ -2271,7 +2294,7 @@ runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" + "import java.util.Arrays;\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.Iterator;\r\n" - + "import java.util.List;\r\n" + "\r\n" + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + + "import java.util.List;\r\n" + "\r\n" + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" + " return null;\r\n" + " }\r\n" + " List list;\r\n" + " HashMap hashMap;\r\n" + " Collection wildCollection;\r\n" + " Collection integerCollection;\r\n" + " @Override\r\n" @@ -2296,11 +2319,11 @@ } /** - * Apache ToStringbuilder - custom array toString and limit of elements, unique names needed + * Custom ToString() builder - custom array toString and limit of elements, unique names needed * * @throws Exception */ - public void testApacheBuilderArrayLimitUnique() throws Exception { + public void testCustomBuilderArrayLimitUnique() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " int[] intArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " List list;\r\n" + " HashMap hashMap;\r\n" + " Collection wildCollection;\r\n" + " Collection integerCollection;\r\n" + " Object builder;\r\n" + " Object buffer;\r\n" + " Object maxLen;\r\n" @@ -2314,7 +2337,7 @@ runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" + "import java.util.Arrays;\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.Iterator;\r\n" - + "import java.util.List;\r\n" + "\r\n" + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + + "import java.util.List;\r\n" + "\r\n" + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " int[] intArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " List list;\r\n" + " HashMap hashMap;\r\n" + " Collection wildCollection;\r\n" + " Collection integerCollection;\r\n" + " Object builder;\r\n" + " Object buffer;\r\n" + " Object maxLen;\r\n" + " Object len;\r\n" + " Object collection;\r\n" + " Object array;\r\n" + " @Override\r\n" + " public String toString() {\r\n" + " final int maxLen2 = 10;\r\n" + " ToStringBuilder builder2 = new ToStringBuilder(this);\r\n" @@ -2337,11 +2360,11 @@ } /** - * Apache ToStringbuilder - skip nulls, use keyword this, no one-line blocks + * Custom ToString() builder - skip nulls, use keyword this, no one-line blocks * * @throws Exception */ - public void testApacheBuilderNullsThisNoBlocks() throws Exception { + public void testCustomBuilderNullsThisNoBlocks() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" @@ -2358,7 +2381,7 @@ runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" - + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" + " return null;\r\n" + " }\r\n" + " List list;\r\n" + " HashMap hashMap;\r\n" + " Collection wildCollection;\r\n" + " Collection integerCollection;\r\n" + " @Override\r\n" + " public String toString() {\r\n" + " ToStringBuilder builder = new ToStringBuilder(this);\r\n" @@ -2375,11 +2398,11 @@ } /** - * Apache ToStringbuilder - custom array, limit elements, skip nulls + * Custom ToString() builder - custom array, limit elements, skip nulls * * @throws Exception */ - public void testApacheBuilderArrayLimitNulls() throws Exception { + public void testCustomBuilderArrayLimitNulls() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" @@ -2396,7 +2419,7 @@ runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" + "import java.util.Arrays;\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.Iterator;\r\n" - + "import java.util.List;\r\n" + "\r\n" + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + + "import java.util.List;\r\n" + "\r\n" + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " Object object;\r\n" + " A anA;\r\n" + " int[] intArray;\r\n" + " float[] floatArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " char[] charArrayMethod() {\r\n" + " return new char[0];\r\n" + " }\r\n" + " float[] floatArrayMethod() {\r\n" + " return null;\r\n" + " }\r\n" + " List list;\r\n" + " HashMap hashMap;\r\n" + " Collection wildCollection;\r\n" + " Collection integerCollection;\r\n" + " @Override\r\n" @@ -2422,23 +2445,24 @@ } /** - * Apache ToStringbuilder, chained calls - basic case + * Custom ToString() builder - chained calls * * @throws Exception */ - public void testChainedApacheBuilder() throws Exception { + public void testChainedCustomBuilder() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + "\r\n" + "}", true, null); IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aBool", "aString", "anInt" }); - fSettings2.toStringStyle= 5; + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.chainCalls= true; runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" - + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" @@ -2465,11 +2489,11 @@ } /** - * Apache ToStringbuilder, chained calls - skip nulls + * Custom ToString() builder - chained calls, skip nulls * * @throws Exception */ - public void testChainedApacheBuilderNulls() throws Exception { + public void testChainedCustomBuilderNulls() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" @@ -2477,10 +2501,11 @@ IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aString", "aBool", "anInt" }); fSettings2.skipNulls= true; - fSettings2.toStringStyle= 5; + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.chainCalls= true; runOperation(a.getType("A"), members, null); - String expected= "package p;\r\n" + "\r\n" + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + String expected= "package p;\r\n" + "\r\n" + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + " @Override\r\n" + " public String toString() {\r\n" + " ToStringBuilder builder = new ToStringBuilder(this);\r\n" + " if (aStringMethod() != null) {\r\n" + " builder.append(\"aStringMethod()\", aStringMethod());\r\n" + " }\r\n" @@ -2492,11 +2517,11 @@ } /** - * Apache ToStringbuilder, chained calls - add comment + * Custom ToString() builder - chained calls, add comment * * @throws Exception */ - public void testChainedApacheBuilderComments() throws Exception { + public void testChainedCustomBuilderComments() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" @@ -2504,12 +2529,13 @@ IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aString", "aBool", "anInt" }); fSettings2.createComments= true; - fSettings2.toStringStyle= 5; + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.chainCalls= true; runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" - + "import org.apache.commons.lang.builder.ToStringBuilder;\r\n" + + "import com.pack.ToStringBuilder;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" @@ -2539,36 +2565,66 @@ } /** - * Spring ToStringCreator - basic case + * Custom toString() builder - alternative class, basic case * * @throws Exception */ - public void testSpringCreator() throws Exception { + public void testAlternativeCustomBuilder() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + "\r\n" + "}", true, null); IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aBool", "aString", "anInt" }); - fSettings2.toStringStyle= 6; + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.className= "org.another.pack.AnotherToStringCreator"; + fSettings2.customBuilderSettings.label= "creator"; + fSettings2.customBuilderSettings.appendMethod= "addSth"; + fSettings2.customBuilderSettings.resultMethod= "getResult"; runOperation(a.getType("A"), members, null); - String expected= "package p;\r\n" + "\r\n" + "import org.springframework.core.style.ToStringCreator;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" - + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" - + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + " @Override\r\n" + " public String toString() {\r\n" - + " ToStringCreator creator = new ToStringCreator(this);\r\n" + " creator.append(\"aStringMethod()\", aStringMethod());\r\n" - + " creator.append(\"aFloatMethod()\", aFloatMethod());\r\n" + " creator.append(\"anArrayMethod()\", anArrayMethod());\r\n" + " creator.append(\"aBool\", aBool);\r\n" - + " creator.append(\"aString\", aString);\r\n" + " creator.append(\"anInt\", anInt);\r\n" + " return creator.toString();\r\n" + " }\r\n" + "\r\n" + "}"; + String expected= "package p;\r\n" + + "\r\n" + + "import org.another.pack.AnotherToStringCreator;\r\n" + + "\r\n" + + "public class A {\r\n" + + " \r\n" + + " boolean aBool;\r\n" + + " int anInt;\r\n" + + " String aString;\r\n" + + " A anA;\r\n" + + " float aFloatMethod() {\r\n" + + " return 3.3f;\r\n" + + " }\r\n" + + " String aStringMethod() {\r\n" + + " return \"\";\r\n" + + " }\r\n" + + " int[] anArrayMethod() {\r\n" + + " return new int[0];\r\n" + + " }\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " AnotherToStringCreator creator = new AnotherToStringCreator(this);\r\n" + + " creator.addSth(aStringMethod(), \"aStringMethod()\");\r\n" + + " creator.addSth(aFloatMethod(), \"aFloatMethod()\");\r\n" + + " creator.addSth(anArrayMethod(), \"anArrayMethod()\");\r\n" + + " creator.addSth(aBool, \"aBool\");\r\n" + + " creator.addSth(aString, \"aString\");\r\n" + + " creator.addSth(\"anInt\", anInt);\r\n" + + " return creator.getResult();\r\n" + + " }\r\n" + + "\r\n" + + "}"; compareSource(expected, a.getSource()); } /** - * Spring ToStringCreator - unique names needed + * Custom toString() builder - alternative class, unique names needed * * @throws Exception */ - public void testSpringCreatorUnique() throws Exception { + public void testAlternativeCustomBuilderUnique() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " int[] intArray;\r\n" + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " List list;\r\n" @@ -2577,29 +2633,70 @@ IMember[] members= getMembers(a.getType("A"), new String[] { "aBool", "intArray", "stringArray", "AArray", "list", "hashMap", "wildCollection", "integerCollection", "builder", "buffer", "maxLen", "len", "collection", "array", "creator" }); - fSettings2.toStringStyle= 6; + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.className= "org.another.pack.AnotherToStringCreator"; + fSettings2.customBuilderSettings.label= "creator"; + fSettings2.customBuilderSettings.appendMethod= "addSth"; + fSettings2.customBuilderSettings.resultMethod= "getResult"; runOperation(a.getType("A"), members, null); - String expected= "package p;\r\n" + "\r\n" + "import java.util.Collection;\r\n" + "import java.util.HashMap;\r\n" + "import java.util.List;\r\n" + "\r\n" - + "import org.springframework.core.style.ToStringCreator;\r\n" + "\r\n" + "public class A {\r\n" + "\r\n" + " boolean aBool;\r\n" + " int[] intArray;\r\n" - + " String[] stringArray;\r\n" + " A[] AArray;\r\n" + " List list;\r\n" + " HashMap hashMap;\r\n" + " Collection wildCollection;\r\n" + " Collection integerCollection;\r\n" - + " Object builder;\r\n" + " Object buffer;\r\n" + " Object maxLen;\r\n" + " Object len;\r\n" + " Object collection;\r\n" + " Object array;\r\n" + " Object creator;\r\n" - + " @Override\r\n" + " public String toString() {\r\n" + " ToStringCreator creator2 = new ToStringCreator(this);\r\n" + " creator2.append(\"aBool\", aBool);\r\n" - + " creator2.append(\"intArray\", intArray);\r\n" + " creator2.append(\"stringArray\", stringArray);\r\n" + " creator2.append(\"AArray\", AArray);\r\n" - + " creator2.append(\"list\", list);\r\n" + " creator2.append(\"hashMap\", hashMap);\r\n" + " creator2.append(\"wildCollection\", wildCollection);\r\n" - + " creator2.append(\"integerCollection\", integerCollection);\r\n" + " creator2.append(\"builder\", builder);\r\n" + " creator2.append(\"buffer\", buffer);\r\n" - + " creator2.append(\"maxLen\", maxLen);\r\n" + " creator2.append(\"len\", len);\r\n" + " creator2.append(\"collection\", collection);\r\n" - + " creator2.append(\"array\", array);\r\n" + " creator2.append(\"creator\", creator);\r\n" + " return creator2.toString();\r\n" + " }\r\n" + "}\r\n" + ""; + String expected= "package p;\r\n" + + "\r\n" + + "import java.util.Collection;\r\n" + + "import java.util.HashMap;\r\n" + + "import java.util.List;\r\n" + + "\r\n" + + "import org.another.pack.AnotherToStringCreator;\r\n" + + "\r\n" + + "public class A {\r\n" + + "\r\n" + + " boolean aBool;\r\n" + + " int[] intArray;\r\n" + + " String[] stringArray;\r\n" + + " A[] AArray;\r\n" + + " List list;\r\n" + + " HashMap hashMap;\r\n" + + " Collection wildCollection;\r\n" + + " Collection integerCollection;\r\n" + + " Object builder;\r\n" + + " Object buffer;\r\n" + + " Object maxLen;\r\n" + + " Object len;\r\n" + + " Object collection;\r\n" + + " Object array;\r\n" + + " Object creator;\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " AnotherToStringCreator creator2 = new AnotherToStringCreator(this);\r\n" + + " creator2.addSth(aBool, \"aBool\");\r\n" + + " creator2.addSth(intArray, \"intArray\");\r\n" + + " creator2.addSth(stringArray, \"stringArray\");\r\n" + + " creator2.addSth(AArray, \"AArray\");\r\n" + + " creator2.addSth(list, \"list\");\r\n" + + " creator2.addSth(hashMap, \"hashMap\");\r\n" + + " creator2.addSth(wildCollection, \"wildCollection\");\r\n" + + " creator2.addSth(integerCollection, \"integerCollection\");\r\n" + + " creator2.addSth(builder, \"builder\");\r\n" + + " creator2.addSth(buffer, \"buffer\");\r\n" + + " creator2.addSth(maxLen, \"maxLen\");\r\n" + + " creator2.addSth(len, \"len\");\r\n" + + " creator2.addSth(collection, \"collection\");\r\n" + + " creator2.addSth(array, \"array\");\r\n" + + " creator2.addSth(creator, \"creator\");\r\n" + + " return creator2.getResult();\r\n" + + " }\r\n" + + "}\r\n" + + ""; compareSource(expected, a.getSource()); } /** - * String ToStringCreator - skip nulls + * Custom toString() builder - alternative class, skip nulls * * @throws Exception */ - public void testSpringCreatorNulls() throws Exception { + public void testAlternativeCustomBuilderNulls() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" @@ -2607,38 +2704,16 @@ IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aString", "aBool", "anInt" }); fSettings2.skipNulls= true; - fSettings2.toStringStyle= 6; - runOperation(a.getType("A"), members, null); - - String expected= "package p;\r\n" + "\r\n" + "import org.springframework.core.style.ToStringCreator;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" - + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" - + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + " @Override\r\n" + " public String toString() {\r\n" - + " ToStringCreator creator = new ToStringCreator(this);\r\n" + " if (aStringMethod() != null) {\r\n" + " creator.append(\"aStringMethod()\", aStringMethod());\r\n" + " }\r\n" - + " creator.append(\"aFloatMethod()\", aFloatMethod());\r\n" + " if (anArrayMethod() != null) {\r\n" + " creator.append(\"anArrayMethod()\", anArrayMethod());\r\n" + " }\r\n" - + " if (aString != null) {\r\n" + " creator.append(\"aString\", aString);\r\n" + " }\r\n" + " creator.append(\"aBool\", aBool);\r\n" + " creator.append(\"anInt\", anInt);\r\n" - + " return creator.toString();\r\n" + " }\r\n" + "\r\n" + "}"; - - compareSource(expected, a.getSource()); - } - - /** - * Spring ToStringCreator, chained calls - basic case - * - * @throws Exception - */ - public void testChainedSpringCreator() throws Exception { - - ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" - + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" - + " return new int[0];\r\n" + " }\r\n" + "\r\n" + "}", true, null); - - IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aBool", "aString", "anInt" }); - fSettings2.toStringStyle= 7; + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.className= "org.another.pack.AnotherToStringCreator"; + fSettings2.customBuilderSettings.label= "creator"; + fSettings2.customBuilderSettings.appendMethod= "addSth"; + fSettings2.customBuilderSettings.resultMethod= "getResult"; runOperation(a.getType("A"), members, null); String expected= "package p;\r\n" + "\r\n" - + "import org.springframework.core.style.ToStringCreator;\r\n" + + "import org.another.pack.AnotherToStringCreator;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" @@ -2657,36 +2732,204 @@ + " }\r\n" + " @Override\r\n" + " public String toString() {\r\n" - + " ToStringCreator creator = new ToStringCreator(this);\r\n" - + " creator.append(\"aStringMethod()\", aStringMethod()).append(\"aFloatMethod()\", aFloatMethod()).append(\"anArrayMethod()\", anArrayMethod()).append(\"aBool\", aBool).append(\"aString\", aString).append(\"anInt\", anInt);\r\n" - + " return creator.toString();\r\n" + " }\r\n" + "\r\n" + "}"; + + " AnotherToStringCreator creator = new AnotherToStringCreator(this);\r\n" + + " if (aStringMethod() != null) {\r\n" + + " creator.addSth(aStringMethod(), \"aStringMethod()\");\r\n" + + " }\r\n" + + " creator.addSth(aFloatMethod(), \"aFloatMethod()\");\r\n" + + " if (anArrayMethod() != null) {\r\n" + + " creator.addSth(anArrayMethod(), \"anArrayMethod()\");\r\n" + + " }\r\n" + + " if (aString != null) {\r\n" + + " creator.addSth(aString, \"aString\");\r\n" + + " }\r\n" + + " creator.addSth(aBool, \"aBool\");\r\n" + + " creator.addSth(\"anInt\", anInt);\r\n" + + " return creator.getResult();\r\n" + + " }\r\n" + + "\r\n" + + "}"; compareSource(expected, a.getSource()); } /** - * String ToStringCreator, chained calls - skip nulls + * Custom toString() builder - alternative class, chained calls * * @throws Exception */ - public void testChainedSpringCreatorNulls() throws Exception { + public void testChainedAlternativeCustomBuilderCreator() throws Exception { ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + "\r\n" + "}", true, null); - IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aString", "aBool", "anInt" }); + IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "aFloatMethod", "anArrayMethod", "aBool", "aString", "anInt" }); + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.className= "org.another.pack.AnotherToStringCreator"; + fSettings2.customBuilderSettings.label= "creator"; + fSettings2.customBuilderSettings.appendMethod= "addSth"; + fSettings2.customBuilderSettings.resultMethod= "getResult"; + fSettings2.customBuilderSettings.chainCalls= true; + runOperation(a.getType("A"), members, null); + + String expected= "package p;\r\n" + + "\r\n" + + "import org.another.pack.AnotherToStringCreator;\r\n" + + "\r\n" + + "public class A {\r\n" + + " \r\n" + + " boolean aBool;\r\n" + + " int anInt;\r\n" + + " String aString;\r\n" + + " A anA;\r\n" + + " float aFloatMethod() {\r\n" + + " return 3.3f;\r\n" + + " }\r\n" + + " String aStringMethod() {\r\n" + + " return \"\";\r\n" + + " }\r\n" + + " int[] anArrayMethod() {\r\n" + + " return new int[0];\r\n" + + " }\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " AnotherToStringCreator creator = new AnotherToStringCreator(this);\r\n" + + " creator.addSth(aStringMethod(), \"aStringMethod()\").addSth(aFloatMethod(), \"aFloatMethod()\").addSth(anArrayMethod(), \"anArrayMethod()\").addSth(aBool, \"aBool\");\r\n" + + " creator.addSth(aString, \"aString\").addSth(\"anInt\", anInt);\r\n" + + " return creator.getResult();\r\n" + + " }\r\n" + + "\r\n" + + "}"; + + compareSource(expected, a.getSource()); + } + + /** + * Custom toString() builder - alternative class, chained calls, skip nulls + * + * @throws Exception + */ + public void testChainedAlternativeCustomBuilderNulls() throws Exception { + + ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + + " return new int[0];\r\n" + " }\r\n" + "\r\n" + "}", true, null); + + IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "anArrayMethod", "aString", "aFloatMethod", "aBool", "anInt" }); + fSettings2.skipNulls= true; + fSettings2.toStringStyle= 4; + fSettings2.customBuilderSettings.className= "org.another.pack.AnotherToStringCreator"; + fSettings2.customBuilderSettings.label= "creator"; + fSettings2.customBuilderSettings.appendMethod= "addSth"; + fSettings2.customBuilderSettings.resultMethod= "getResult"; + fSettings2.customBuilderSettings.chainCalls= true; + runOperation(a.getType("A"), members, null); + + String expected= "package p;\r\n" + + "\r\n" + + "import org.another.pack.AnotherToStringCreator;\r\n" + + "\r\n" + + "public class A {\r\n" + + " \r\n" + + " boolean aBool;\r\n" + + " int anInt;\r\n" + + " String aString;\r\n" + + " A anA;\r\n" + + " float aFloatMethod() {\r\n" + + " return 3.3f;\r\n" + + " }\r\n" + + " String aStringMethod() {\r\n" + + " return \"\";\r\n" + + " }\r\n" + + " int[] anArrayMethod() {\r\n" + + " return new int[0];\r\n" + + " }\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " AnotherToStringCreator creator = new AnotherToStringCreator(this);\r\n" + + " if (aStringMethod() != null) {\r\n" + + " creator.addSth(aStringMethod(), \"aStringMethod()\");\r\n" + + " }\r\n" + + " if (anArrayMethod() != null) {\r\n" + + " creator.addSth(anArrayMethod(), \"anArrayMethod()\");\r\n" + + " }\r\n" + + " if (aString != null) {\r\n" + + " creator.addSth(aString, \"aString\");\r\n" + + " }\r\n" + + " creator.addSth(aFloatMethod(), \"aFloatMethod()\").addSth(aBool, \"aBool\");\r\n" + + " creator.addSth(\"anInt\", anInt);\r\n" + + " return creator.getResult();\r\n" + + " }\r\n" + + "\r\n" + + "}"; + + compareSource(expected, a.getSource()); + } + + /** + * Custom toString() builder - alternative class with append method that takes only one argument + * for most of the types + * + * @throws Exception + */ + public void testChainedOneArgumentCustomBuilders() throws Exception { + + ICompilationUnit a= fPackageP.createCompilationUnit("A.java", "package p;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" + " int anInt;\r\n" + " String aString;\r\n" + + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" + " }\r\n" + " int[] anArrayMethod() {\r\n" + + " return new int[0];\r\n" + " }\r\n" + "\r\n" + "}", true, null); + + IPackageFragment packageFragment= fRoot.createPackageFragment("com.simple.pack", true, null); + ICompilationUnit compilationUnit= packageFragment.getCompilationUnit("ToStringBuilder.java"); + compilationUnit + .createType( + "package com.simple.pack;\npublic class ToStringBuilder {\npublic ToStringBuilder(Object o){\n}\npublic ToStringBuilder append(Object o){\nreturn null;\n}\npublic ToStringBuilder append(String s1, String s2) {\nreturn null;\n}\npublic String toString(){\nreturn null;\n}\n}\n", + null, true, null); + + IMember[] members= getMembers(a.getType("A"), new String[] { "aStringMethod", "anArrayMethod", "aString", "aFloatMethod", "aBool", "anInt" }); fSettings2.skipNulls= true; - fSettings2.toStringStyle= 7; + fSettings2.customBuilderSettings.className= "com.simple.pack.ToStringBuilder"; + fSettings2.toStringStyle= 4; runOperation(a.getType("A"), members, null); - String expected= "package p;\r\n" + "\r\n" + "import org.springframework.core.style.ToStringCreator;\r\n" + "\r\n" + "public class A {\r\n" + " \r\n" + " boolean aBool;\r\n" - + " int anInt;\r\n" + " String aString;\r\n" + " A anA;\r\n" + " float aFloatMethod() {\r\n" + " return 3.3f;\r\n" + " }\r\n" + " String aStringMethod() {\r\n" + " return \"\";\r\n" - + " }\r\n" + " int[] anArrayMethod() {\r\n" + " return new int[0];\r\n" + " }\r\n" + " @Override\r\n" + " public String toString() {\r\n" - + " ToStringCreator creator = new ToStringCreator(this);\r\n" + " if (aStringMethod() != null) {\r\n" + " creator.append(\"aStringMethod()\", aStringMethod());\r\n" + " }\r\n" - + " creator.append(\"aFloatMethod()\", aFloatMethod());\r\n" + " if (anArrayMethod() != null) {\r\n" + " creator.append(\"anArrayMethod()\", anArrayMethod());\r\n" + " }\r\n" - + " if (aString != null) {\r\n" + " creator.append(\"aString\", aString);\r\n" + " }\r\n" + " creator.append(\"aBool\", aBool).append(\"anInt\", anInt);\r\n" - + " return creator.toString();\r\n" + " }\r\n" + "\r\n" + "}"; + String expected= "package p;\r\n" + + "\r\n" + + "import com.simple.pack.ToStringBuilder;\r\n" + + "\r\n" + + "public class A {\r\n" + + " \r\n" + + " boolean aBool;\r\n" + + " int anInt;\r\n" + + " String aString;\r\n" + + " A anA;\r\n" + + " float aFloatMethod() {\r\n" + + " return 3.3f;\r\n" + + " }\r\n" + + " String aStringMethod() {\r\n" + + " return \"\";\r\n" + + " }\r\n" + + " int[] anArrayMethod() {\r\n" + + " return new int[0];\r\n" + + " }\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " ToStringBuilder builder = new ToStringBuilder(this);\r\n" + + " if (aStringMethod() != null) {\r\n" + + " builder.append(\"aStringMethod()\", aStringMethod());\r\n" + + " }\r\n" + + " if (anArrayMethod() != null) {\r\n" + + " builder.append(anArrayMethod());\r\n" + + " }\r\n" + + " if (aString != null) {\r\n" + + " builder.append(\"aString\", aString);\r\n" + + " }\r\n" + + " builder.append(aFloatMethod());\r\n" + + " builder.append(aBool);\r\n" + + " builder.append(anInt);\r\n" + + " return builder.toString();\r\n" + + " }\r\n" + + "\r\n" + + "}"; compareSource(expected, a.getSource()); } #P org.eclipse.jdt.ui Index: core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.properties,v retrieving revision 1.30 diff -u -r1.30 CodeGenerationMessages.properties --- core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.properties 30 Mar 2009 10:45:07 -0000 1.30 +++ core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.properties 17 Apr 2009 14:18:18 -0000 @@ -8,6 +8,7 @@ # Contributors: # IBM Corporation - initial API and implementation # Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 +# Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 ############################################################################### AddGetterSetterOperation_description=Generate Getters and Setters... AddGetterSetterOperation_error_input_type_not_found=Could not find the selected type element @@ -35,8 +36,7 @@ GenerateHashCodeEqualsOperation_hash_code_argument=the array to create a hash code value for GenerateHashCodeEqualsOperation_tag_return=@return GenerateHashCodeEqualsOperation_return_comment=a hash code value for the array -GenerateToStringOperation_apache_ToStringBilder_chained_style_name=Apache ToStringBuilder - chained calls -GenerateToStringOperation_apache_ToStringBuilder_style_name=Apache ToStringBuilder +GenerateToStringOperation_customStringBuilder_style_name=Custom toString() builder GenerateToStringOperation_objectClassNameVariableDescription=Inserts the name of this class GenerateToStringOperation_objectClassGetNameVariableDescription=Inserts a call to this.getClass().getName() @@ -51,10 +51,8 @@ GenerateToStringOperation_description=Adding toString() method... GenerateToStringOperation_error_dialog_title=Problem with toString() generation GenerateToStringOperation_invalid_message=The extension ''{0}'' has become invalid. -GenerateToStringOperation_spring_ToStringCreator_chained_style_name=Spring ToStringCreator - chained calls -GenerateToStringOperation_spring_ToStringCreator_style_name=Spring ToStringCreator GenerateToStringOperation_string_format_style_name=String.format/MessageFormat GenerateToStringOperation_StringBuilder_chained_style_name=StringBuilder/StringBuffer - chained calls GenerateToStringOperation_stringBuilder_style_name=StringBuilder/StringBuffer GenerateToStringOperation_stringConcatenation_style_name=String concatenation -GenerateToStringOperation_warning_no_arrays_collections_with_this_style=It is not recommended to enable "Ignore arrays' default toString" or "Limit number of items in arrays/collections/maps" options with selected code style as it might lead to undesired results. +GenerateToStringOperation_warning_no_arrays_collections_with_this_style=It is not recommended to enable "List contents of arrays instead of using native toString" or "Limit number of items in arrays/collections/maps" options with selected code style as it might lead to undesired results. Index: core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.java,v retrieving revision 1.18 diff -u -r1.18 CodeGenerationMessages.java --- core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.java 30 Mar 2009 10:45:07 -0000 1.18 +++ core extension/org/eclipse/jdt/internal/corext/codemanipulation/CodeGenerationMessages.java 17 Apr 2009 14:18:18 -0000 @@ -45,8 +45,7 @@ public static String GenerateHashCodeEqualsOperation_hash_code_argument; public static String GenerateHashCodeEqualsOperation_tag_return; public static String GenerateHashCodeEqualsOperation_return_comment; - public static String GenerateToStringOperation_apache_ToStringBilder_chained_style_name; - public static String GenerateToStringOperation_apache_ToStringBuilder_style_name; + public static String GenerateToStringOperation_customStringBuilder_style_name; public static String GenerateToStringOperation_objectClassGetNameVariableDescription; public static String GenerateToStringOperation_objectClassNameVariableDescription; public static String GenerateToStringOperation_objectHashCodeVariableDescription; @@ -59,8 +58,6 @@ public static String GenerateToStringOperation_memberNameVariableDescription; public static String GenerateToStringOperation_memberValueVariableDescription; public static String GenerateToStringOperation_otherFieldsVariableDescription; - public static String GenerateToStringOperation_spring_ToStringCreator_chained_style_name; - public static String GenerateToStringOperation_spring_ToStringCreator_style_name; public static String GenerateToStringOperation_string_format_style_name; public static String GenerateToStringOperation_StringBuilder_chained_style_name; public static String GenerateToStringOperation_stringBuilder_style_name; Index: core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationSettings.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationSettings.java,v retrieving revision 1.1 diff -u -r1.1 ToStringGenerationSettings.java --- core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationSettings.java 9 Mar 2009 19:20:35 -0000 1.1 +++ core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationSettings.java 17 Apr 2009 14:18:19 -0000 @@ -7,6 +7,7 @@ * * Contributors: * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 + * Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 *******************************************************************************/ package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration; @@ -31,7 +32,40 @@ public static final String SETTINGS_TEMPLATE_NAMES= "ToStringTemplateNames"; //$NON-NLS-1$ - public static final String SETTINGS_TEMPLATES= "ToStringTemplates"; //$NON-NLS-1$ + public static final String SETTINGS_TEMPLATES= "ToStringTemplates"; //$NON-NLS-1$ + + public static final String SETTINGS_CUSTOMBUILDER_CLASS= "CustomBuilderClass"; //$NON-NLS-1$ + + public static final String SETTINGS_CUSTOMBUILDER_LABEL= "CustomBuilderLabel"; //$NON-NLS-1$ + + public static final String SETTINGS_CUSTOMBUILDER_APPENDMETHOD= "CustomBuilderAppendMethod"; //$NON-NLS-1$ + + public static final String SETTINGS_CUSTOMBUILDER_RESULTMETHOD= "CustomBuilderResultMethod"; //$NON-NLS-1$ + + public static final String SETTINGS_CUSTOMBUILDER_CHAINCALLS= "CustomBuilderChainCalls"; //$NON-NLS-1$ + + /** + * Container for settings specific for custom toString() generator code style + */ + public static class CustomBuilderSettings { + /** + * what class should be used as a custom toString() builder (this is a fully qualified and + * Parameterized name) + **/ + public String className; + + /** identifier for a custom toString() builder in generated code **/ + public String label; + + /** name of a custom toString() builder's methods that should be called to append content **/ + public String appendMethod; + + /** name of a custom toString() builder method that should be called to retrieve result **/ + public String resultMethod; + + /** should custom toString() builder method calls be joined into chains? **/ + public boolean chainCalls; + } /** which template should be used to format the output of the toString() method? */ public int stringFormatTemplateNumber; @@ -70,20 +104,32 @@ /** can generated code use jdk 1.6 API? **/ public boolean is60orHigher; + /** settings specific for custom builder code style **/ + public CustomBuilderSettings customBuilderSettings; + + private IDialogSettings dialogSettings; + public ToStringGenerationSettings(IDialogSettings dialogSettings) { + this.dialogSettings= dialogSettings; limitElements= asBoolean(dialogSettings.get(SETTINGS_LIMITELEMENTS), false); customArrayToString= asBoolean(dialogSettings.get(SETTINGS_IGNOREDEFAULT), true); toStringStyle= asInt(dialogSettings.get(SETTINGS_STRINGSTYLE), 0); limitValue= asInt(dialogSettings.get(SETTINGS_LIMITVALUE), 10); skipNulls= asBoolean(dialogSettings.get(SETTINGS_SKIPNULLS), false); stringFormatTemplateNumber= asInt(dialogSettings.get(SETTINGS_SELECTED_TEMPLATE), 0); + customBuilderSettings= new CustomBuilderSettings(); + customBuilderSettings.className= asString(dialogSettings.get(SETTINGS_CUSTOMBUILDER_CLASS), ""); //$NON-NLS-1$ + customBuilderSettings.label= asString(dialogSettings.get(SETTINGS_CUSTOMBUILDER_LABEL), "builder"); //$NON-NLS-1$ + customBuilderSettings.appendMethod= asString(dialogSettings.get(SETTINGS_CUSTOMBUILDER_APPENDMETHOD), "append"); //$NON-NLS-1$ + customBuilderSettings.resultMethod= asString(dialogSettings.get(SETTINGS_CUSTOMBUILDER_RESULTMETHOD), "toString"); //$NON-NLS-1$ + customBuilderSettings.chainCalls= asBoolean(dialogSettings.get(SETTINGS_CUSTOMBUILDER_CHAINCALLS), false); } public ToStringGenerationSettings() { } - public void writeDialogSettings(IDialogSettings dialogSettings) { + public void writeDialogSettings() { dialogSettings.put(SETTINGS_LIMITELEMENTS, limitElements); dialogSettings.put(SETTINGS_IGNOREDEFAULT, customArrayToString); dialogSettings.put(SETTINGS_STRINGSTYLE, toStringStyle); @@ -91,18 +137,56 @@ dialogSettings.put(SETTINGS_SKIPNULLS, skipNulls); dialogSettings.put(SETTINGS_SELECTED_TEMPLATE, stringFormatTemplateNumber); } - + + /** + * Returns a copy of customBuilderSettings. Changes made in the returned object will not affect + * this settings object. To save changes made in returned object, use + * {@link #writeCustomBuilderSettings(ToStringGenerationSettings.CustomBuilderSettings)}. + * + * @return copy of custom builder settings object + */ + public CustomBuilderSettings getCustomBuilderSettings() { + CustomBuilderSettings result= new CustomBuilderSettings(); + result.className= customBuilderSettings.className; + result.label= customBuilderSettings.label; + result.appendMethod= customBuilderSettings.appendMethod; + result.resultMethod= customBuilderSettings.resultMethod; + result.chainCalls= customBuilderSettings.chainCalls; + return result; + } + + /** + * Writes given custom builder settings object to the underlying dialog settings. + * + * @param customBuilderSettings1 settings to save + */ + public void writeCustomBuilderSettings(CustomBuilderSettings customBuilderSettings1) { + dialogSettings.put(SETTINGS_CUSTOMBUILDER_CLASS, customBuilderSettings1.className); + dialogSettings.put(SETTINGS_CUSTOMBUILDER_LABEL, customBuilderSettings1.label); + dialogSettings.put(SETTINGS_CUSTOMBUILDER_APPENDMETHOD, customBuilderSettings1.appendMethod); + dialogSettings.put(SETTINGS_CUSTOMBUILDER_RESULTMETHOD, customBuilderSettings1.resultMethod); + dialogSettings.put(SETTINGS_CUSTOMBUILDER_CHAINCALLS, customBuilderSettings1.chainCalls); + customBuilderSettings= customBuilderSettings1; + } + private boolean asBoolean(String string, boolean defaultValue) { if (string != null) { return StringConverter.asBoolean(string, defaultValue); } return defaultValue; } - + private static int asInt(String string, int defaultValue) { if (string != null) { return StringConverter.asInt(string, defaultValue); } return defaultValue; } -} \ No newline at end of file + + private static String asString(String string, String defaultValue) { + if (string != null) { + return string; + } + return defaultValue; + } +} Index: core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/GenerateToStringOperation.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/GenerateToStringOperation.java,v retrieving revision 1.1 diff -u -r1.1 GenerateToStringOperation.java --- core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/GenerateToStringOperation.java 9 Mar 2009 19:20:35 -0000 1.1 +++ core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/GenerateToStringOperation.java 17 Apr 2009 14:18:19 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 Mateusz Matela and others. + * Copyright (c) 2009 Mateusz Matela and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 + * Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 *******************************************************************************/ package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration; @@ -171,28 +172,15 @@ public static final int STRING_FORMAT= 3; - public static final int APACHE_BUILDER= 4; - - public static final int APACHE_BUILDER_CHAINED= 5; - - public static final int SPRING_CREATOR= 6; - - public static final int SPRING_CREATOR_CHAINED= 7; - -// public static final int ID_START= 8; + public static final int CUSTOM_BUILDER= 4; private final static String[] hardcoded_styles= { CodeGenerationMessages.GenerateToStringOperation_stringConcatenation_style_name, CodeGenerationMessages.GenerateToStringOperation_stringBuilder_style_name, CodeGenerationMessages.GenerateToStringOperation_StringBuilder_chained_style_name, CodeGenerationMessages.GenerateToStringOperation_string_format_style_name, -// CodeGenerationMessages.GenerateToStringOperation_apache_ToStringBuilder_style_name, -// CodeGenerationMessages.GenerateToStringOperation_apache_ToStringBilder_chained_style_name, -// CodeGenerationMessages.GenerateToStringOperation_spring_ToStringCreator_style_name, -// CodeGenerationMessages.GenerateToStringOperation_spring_ToStringCreator_chained_style_name - }; - - + CodeGenerationMessages.GenerateToStringOperation_customStringBuilder_style_name + }; /** * @return Array containing names of implemented code styles @@ -217,17 +205,10 @@ return new StringBuilderChainGenerator(); case STRING_FORMAT: return new StringFormatGenerator(); - case APACHE_BUILDER: - return new ApacheBuilderSpringCreatorGenerator("org.apache.commons.lang.builder.ToStringBuilder", "builder", false); //$NON-NLS-1$ //$NON-NLS-2$ - case APACHE_BUILDER_CHAINED: - return new ApacheBuilderSpringCreatorGenerator("org.apache.commons.lang.builder.ToStringBuilder", "builder", true); //$NON-NLS-1$ //$NON-NLS-2$ - case SPRING_CREATOR: - return new ApacheBuilderSpringCreatorGenerator("org.springframework.core.style.ToStringCreator", "creator", false); //$NON-NLS-1$ //$NON-NLS-2$ - case SPRING_CREATOR_CHAINED: - return new ApacheBuilderSpringCreatorGenerator("org.springframework.core.style.ToStringCreator", "creator", true); //$NON-NLS-1$ //$NON-NLS-2$ + case CUSTOM_BUILDER: + return new CustomBuilderGenerator(); default: - //unknown style - return null; + throw new RuntimeException("Undefined toString() code style: " + toStringStyle); //$NON-NLS-1$ } } @@ -244,10 +225,10 @@ * Creates new GenerateToStringOperation, using settings.toStringStyle * field to choose the right subclass. * - * @param typeBinding binding for the type for which the toString() method will be created + * @param typeBinding binding for the type for which the toString() method will be created * @param selectedBindings bindings for the typetype's members to be used in created method * @param unit a compilation unit containing the type - * @param elementPosition at this position in the compilation unit created method will be added + * @param elementPosition at this position in the compilation unit created method will be added * @param settings the settings for toString() generator * @return a ready to use GenerateToStringOperation object */ Index: core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationContext.java,v retrieving revision 1.1 diff -u -r1.1 ToStringGenerationContext.java --- core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationContext.java 9 Mar 2009 19:20:35 -0000 1.1 +++ core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ToStringGenerationContext.java 17 Apr 2009 14:18:19 -0000 @@ -7,6 +7,7 @@ * * Contributors: * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 + * Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 *******************************************************************************/ package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration; @@ -28,6 +29,8 @@ private ITypeBinding fType; private ToStringGenerationSettings fSettings; + + private ToStringGenerationSettings.CustomBuilderSettings fCustomBuilderSettings; private CompilationUnitRewrite fRewrite; @@ -36,6 +39,7 @@ fParser= parser; fSelectedMembers= selectedMembers; fSettings= settings; + fCustomBuilderSettings= settings.getCustomBuilderSettings(); fType= type; fRewrite= rewrite; } @@ -107,5 +111,25 @@ public boolean isSkipNulls() { return fSettings.skipNulls; } + + public String getCustomBuilderClass() { + return fCustomBuilderSettings.className; + } + + public String getCustomBuilderLabel() { + return fCustomBuilderSettings.label; + } + + public String getCustomBuilderAppendMethod() { + return fCustomBuilderSettings.appendMethod; + } + + public String getCustomBuilderResultMethod() { + return fCustomBuilderSettings.resultMethod; + } + + public boolean isCustomBuilderChainedCalls() { + return fCustomBuilderSettings.chainCalls; + } } \ No newline at end of file Index: core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ApacheBuilderSpringCreatorGenerator.java =================================================================== RCS file: core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ApacheBuilderSpringCreatorGenerator.java diff -N core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ApacheBuilderSpringCreatorGenerator.java --- core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/ApacheBuilderSpringCreatorGenerator.java 9 Mar 2009 19:20:35 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,150 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 Mateusz Matela and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 - *******************************************************************************/ -package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration; - -import org.eclipse.core.runtime.CoreException; - -import org.eclipse.ltk.core.refactoring.RefactoringStatus; - -import org.eclipse.jdt.core.NamingConventions; -import org.eclipse.jdt.core.dom.ClassInstanceCreation; -import org.eclipse.jdt.core.dom.Expression; -import org.eclipse.jdt.core.dom.IfStatement; -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jdt.core.dom.MethodInvocation; -import org.eclipse.jdt.core.dom.ReturnStatement; -import org.eclipse.jdt.core.dom.StringLiteral; -import org.eclipse.jdt.core.dom.VariableDeclarationFragment; -import org.eclipse.jdt.core.dom.VariableDeclarationStatement; -import org.eclipse.jdt.core.dom.InfixExpression.Operator; - -import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationMessages; - - -/** - *

- * Implementation of AbstractToStringGenerator that creates toString() - * method using external library. The library must deliver a stringBuilder with - * append(name, value) method, for example Apache ToStringBuilder or Spring Framework - * ToStringCreator. - *

- *

- * Generated methods look like this: - * - *

- * public String toString() {
- * 	StringBuilder builder= new StringBuilder();
- * 	builder.append("FooClass( field1=");
- * 	builder.append(field1);
- * 	builder.append(", field2=");
- * 	builder.append(field2);
- * 	builder.append(" )");
- * 	return builder.toString();
- * }
- * 
- * - *

- * - * @since 3.5 - */ -public class ApacheBuilderSpringCreatorGenerator extends AbstractToStringGenerator { - private String builderVariableName; - - private String importText; - - private boolean chained; - - public ApacheBuilderSpringCreatorGenerator(String importText, String builderName, boolean chained) { - builderVariableName= builderName; - this.importText= importText; - this.chained= chained; - } - - protected void initialize() { - super.initialize(); - this.builderVariableName= createNameSuggestion(builderVariableName, NamingConventions.VK_PARAMETER); - } - - public RefactoringStatus checkConditions() { - RefactoringStatus status= super.checkConditions(); - if (fContext.isCustomArray() || fContext.isLimitItems()) - status.addWarning(CodeGenerationMessages.GenerateToStringOperation_warning_no_arrays_collections_with_this_style); - return status; - } - - - protected void addElement(Object element) { - } - - public MethodDeclaration generateToStringMethod() throws CoreException { - initialize(); - - //ToStringBuilder builder= new ToStringBuilder(this); - VariableDeclarationFragment fragment= fAst.newVariableDeclarationFragment(); - fragment.setName(fAst.newSimpleName(builderVariableName)); - ClassInstanceCreation classInstance= fAst.newClassInstanceCreation(); - String typeName= addImport(importText); - classInstance.setType(fAst.newSimpleType(fAst.newSimpleName(typeName))); - classInstance.arguments().add(fAst.newThisExpression()); - fragment.setInitializer(classInstance); - VariableDeclarationStatement vStatement= fAst.newVariableDeclarationStatement(fragment); - vStatement.setType(fAst.newSimpleType(fAst.newName(typeName))); - toStringMethod.getBody().statements().add(vStatement); - - Expression expression= null; - - for (int i= 0; i < getContext().getSelectedMembers().length; i++) { - //builder.append("member", member); - StringLiteral literal= fAst.newStringLiteral(); - literal.setLiteralValue(getMemberName(getContext().getSelectedMembers()[i], ToStringTemplateParser.MEMBER_NAME_PARENTHESIS_VARIABLE)); - MethodInvocation appendInvocation= fAst.newMethodInvocation(); - appendInvocation.setName(fAst.newSimpleName("append")); //$NON-NLS-1$ - appendInvocation.arguments().add(literal); - appendInvocation.arguments().add(createMemberAccessExpression(getContext().getSelectedMembers()[i], false, getContext().isSkipNulls())); - - if (getContext().isSkipNulls() && !getMemberType(getContext().getSelectedMembers()[i]).isPrimitive()) { - if (expression != null) { - toStringMethod.getBody().statements().add(fAst.newExpressionStatement(expression)); - expression= null; - } - appendInvocation.setExpression(fAst.newSimpleName(builderVariableName)); - IfStatement ifStatement= fAst.newIfStatement(); - ifStatement.setExpression(createInfixExpression(createMemberAccessExpression(getContext().getSelectedMembers()[i], true, true), Operator.NOT_EQUALS, fAst.newNullLiteral())); - ifStatement.setThenStatement(createOneStatementBlock(appendInvocation)); - toStringMethod.getBody().statements().add(ifStatement); - } else { - if (expression != null) { - appendInvocation.setExpression(expression); - } else { - appendInvocation.setExpression(fAst.newSimpleName(builderVariableName)); - } - if (chained) { - expression= appendInvocation; - } else { - toStringMethod.getBody().statements().add(fAst.newExpressionStatement(appendInvocation)); - } - } - } - - if (expression != null) { - toStringMethod.getBody().statements().add(fAst.newExpressionStatement(expression)); - } - // return builder.toString(); - ReturnStatement rStatement= fAst.newReturnStatement(); - rStatement.setExpression(createMethodInvocation(builderVariableName, "toString", null)); //$NON-NLS-1$ - toStringMethod.getBody().statements().add(rStatement); - - complete(); - - return toStringMethod; - } - -} Index: ui/org/eclipse/jdt/internal/ui/dialogs/GenerateToStringDialog.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/dialogs/GenerateToStringDialog.java,v retrieving revision 1.4 diff -u -r1.4 GenerateToStringDialog.java --- ui/org/eclipse/jdt/internal/ui/dialogs/GenerateToStringDialog.java 30 Mar 2009 13:03:56 -0000 1.4 +++ ui/org/eclipse/jdt/internal/ui/dialogs/GenerateToStringDialog.java 17 Apr 2009 14:18:24 -0000 @@ -8,9 +8,11 @@ * Contributors: * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 * Mateusz Matela - [toString] Template edit dialog has usability issues - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267916 + * Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 *******************************************************************************/ package org.eclipse.jdt.internal.ui.dialogs; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -37,6 +39,7 @@ import org.eclipse.swt.widgets.Spinner; import org.eclipse.swt.widgets.Text; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.IDialogConstants; @@ -58,19 +61,31 @@ import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.ISelectionStatusValidator; +import org.eclipse.ui.dialogs.SelectionDialog; import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.GenerateToStringOperation; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringGenerationSettings; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringTemplateParser; +import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringGenerationSettings.CustomBuilderSettings; +import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.corext.util.Messages; +import org.eclipse.jdt.ui.IJavaElementSearchConstants; import org.eclipse.jdt.ui.JavaElementImageDescriptor; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.JavaPlugin; @@ -80,6 +95,7 @@ import org.eclipse.jdt.internal.ui.util.SWTUtil; import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider; +import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil; /** * Dialog for the generate toString() action. @@ -271,12 +287,14 @@ } } - private static class GenerateToStringValidator implements ISelectionStatusValidator { + private class GenerateToStringValidator implements ISelectionStatusValidator { private int fNumFields; private int fNumMethods; + private CustomBuilderValidator fValidator; + public GenerateToStringValidator(int fields, int methods) { fNumFields= fields; fNumMethods= methods; @@ -284,6 +302,14 @@ public IStatus validate(Object[] selection) { + if (getGenerationSettings().toStringStyle == GenerateToStringOperation.CUSTOM_BUILDER) { + if (fValidator == null) + fValidator= new CustomBuilderValidator(getType().getJavaProject()); + IStatus status= fValidator.revalidateAll(getGenerationSettings().getCustomBuilderSettings()); + if (!status.isOK()) + return new StatusInfo(IStatus.ERROR, JavaUIMessages.GenerateToStringDialog_selectioninfo_customBuilderConfigError); + } + int countFields= 0, countMethods= 0; for (int index= 0; index < selection.length; index++) { if (selection[index] instanceof IVariableBinding) @@ -304,12 +330,12 @@ * Template number, -1 for new template. */ private final int templateNumber; - + /** * Initial template name, can be null. */ private final String fInitialTemplateName; - + private Text templateName; private Text template; @@ -327,7 +353,7 @@ fInitialTemplateName= templateNumber < 0 ? null : (String)templateNames.get(templateNumber); setHelpAvailable(false); } - + protected boolean isResizable() { return true; } @@ -377,7 +403,7 @@ //Ctrl+Enter should execute the default button, workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=145959 template.addTraverseListener(new TraverseListener() { public void keyTraversed(TraverseEvent e) { - if (e.detail == SWT.TRAVERSE_RETURN && (e.stateMask & SWT.MODIFIER_MASK) != 0) { + if (e.detail == SWT.TRAVERSE_RETURN && (e.stateMask & SWT.MODIFIER_MASK) != 0) { buttonPressed(((Integer)getShell().getDefaultButton().getData()).intValue()); } } @@ -400,7 +426,7 @@ private String createNewTemplateName() { if (!templateNames.contains(JavaUIMessages.GenerateToStringDialog_newTemplateName)) return JavaUIMessages.GenerateToStringDialog_newTemplateName; - + int copyCount= 2; String newName; do { @@ -447,25 +473,21 @@ private class Proposal implements IContentProposal { final private String proposal; - private String content; + private int position; public Proposal(String proposal) { this.proposal= proposal; + this.position= proposal.length(); } public String getContent() { - for (int i= 1; i < Math.min(proposal.length(), latestPosition); i++) { - if (proposal.substring(0, i).equals(latestContents.substring(latestPosition - i, latestPosition))) { - return content= proposal.substring(i); - } - } - return proposal; + int overlap= stringOverlap(latestContents.substring(0, latestPosition), proposal); + position= proposal.length() - overlap; + return proposal.substring(overlap); } public int getCursorPosition() { - if (content != null) - return content.length(); - return proposal.length(); + return position; } public String getDescription() { @@ -477,24 +499,51 @@ } } - private IContentProposal[] proposals; - private String latestContents; private int latestPosition; public IContentProposal[] getProposals(String contents, int position) { - if (proposals == null) { - List proposalsList= new ArrayList(); - String[] tokens= parser.getVariables(); - for (int i= 0; i < tokens.length; i++) { - proposalsList.add(new Proposal(tokens[i])); - } - proposals= (IContentProposal[])proposalsList.toArray(new IContentProposal[0]); + List primaryProposals= new ArrayList(); + List secondaryProposals= new ArrayList(); + String[] proposalStrings= parser.getVariables(); + String contentToCursor= contents.substring(0, position); + for (int i= 0; i < proposalStrings.length; i++) { + if (stringOverlap(contentToCursor, proposalStrings[i]) > 0) + primaryProposals.add(new Proposal(proposalStrings[i])); + else + secondaryProposals.add(new Proposal(proposalStrings[i])); } + this.latestContents= contents; this.latestPosition= position; - return proposals; + + primaryProposals.addAll(secondaryProposals); + return (IContentProposal[])primaryProposals.toArray(new IContentProposal[0]); + } + + /** + * Checks if the end of the first string is equal to the beginning of of the second + * string. + * + * @param s1 first String + * @param s2 second String + * @return length of overlapping segment (0 if strings don't overlap) + */ + private int stringOverlap(String s1, String s2) { + int l1= s1.length(); + for (int l= 1; l <= Math.min(s1.length(), s2.length()); l++) { + boolean ok= true; + for (int i= 0; i < l; i++) { + if (s1.charAt(l1 - l + i) != s2.charAt(i)) { + ok= false; + break; + } + } + if (ok) + return l; + } + return 0; } } @@ -568,7 +617,7 @@ templateNames= new ArrayList(Arrays.asList(getTemplateNames())); templates= new ArrayList(Arrays.asList(getTemplates(getDialogSettings()))); - selectedTemplateNumber= fGenerationSettings.stringFormatTemplateNumber; + selectedTemplateNumber= getGenerationSettings().stringFormatTemplateNumber; refreshControls(); templateNameControl.addSelectionListener(new SelectionListener() { @@ -599,7 +648,7 @@ private void applyChanges() { getDialogSettings().put(ToStringGenerationSettings.SETTINGS_TEMPLATE_NAMES, (String[])templateNames.toArray(new String[0])); getDialogSettings().put(ToStringGenerationSettings.SETTINGS_TEMPLATES, (String[])templates.toArray(new String[0])); - fGenerationSettings.stringFormatTemplateNumber= Math.max(selectedTemplateNumber, 0); + getGenerationSettings().stringFormatTemplateNumber= Math.max(selectedTemplateNumber, 0); somethingChanged= false; getButton(APPLY_BUTTON).setEnabled(false); } @@ -680,6 +729,414 @@ } } + private static class CustomBuilderValidator implements ISelectionStatusValidator { + + private final static List fJavaKeyWords= Arrays.asList(new String[] { "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$ + "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$ //$NON-NLS-13$ //$NON-NLS-14$ //$NON-NLS-15$ //$NON-NLS-16$ //$NON-NLS-17$ //$NON-NLS-18$ + "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$ //$NON-NLS-13$ //$NON-NLS-14$ //$NON-NLS-15$ //$NON-NLS-16$ //$NON-NLS-17$ //$NON-NLS-18$ //$NON-NLS-19$ + "while" }); //$NON-NLS-1$ + + private final IJavaProject fJavaProject; + + private IType fLastValidBuilderType; + + private List fLastValidAppendMethodSuggestions; + + private List fLastValidResultMethodSuggestions; + + public CustomBuilderValidator(IJavaProject javaProject) { + fJavaProject= javaProject; + } + + public IStatus validateBuilderType(IType type) { + if (fLastValidBuilderType != null && fLastValidBuilderType.equals(type)) { + return new StatusInfo(); + } + + try { + IMethod[] methods= type.getMethods(); + boolean foundConstructor= false; + for (int i= 0; i < methods.length; i++) { + if (methods[i].isConstructor() && Flags.isPublic(methods[i].getFlags())) { + String[] parameterTypes= methods[i].getParameterTypes(); + if (parameterTypes.length == 1 && "java.lang.Object".equals(JavaModelUtil.getResolvedTypeName(parameterTypes[0], type))) { //$NON-NLS-1$ + foundConstructor= true; + break; + } + } + } + if (!foundConstructor) + return new StatusInfo(IStatus.ERROR, JavaUIMessages.GenerateToStringDialog_customBuilderConfig_noConstructorError); + + List appendMethodSuggestions= getAppendMethodSuggestions(type); + if (appendMethodSuggestions.isEmpty()) + return new StatusInfo(IStatus.ERROR, JavaUIMessages.GenerateToStringDialog_customBuilderConfig_noAppendMethodError); + + List resultMethodSuggestions= getResultMethodSuggestions(type); + if (resultMethodSuggestions.isEmpty()) + return new StatusInfo(IStatus.ERROR, JavaUIMessages.GenerateToStringDialog_customBuilderConfig_noResultMethodError); + + fLastValidBuilderType= type; + fLastValidAppendMethodSuggestions= appendMethodSuggestions; + fLastValidResultMethodSuggestions= resultMethodSuggestions; + return new StatusInfo(); + } catch (JavaModelException e1) { + return new StatusInfo(IStatus.WARNING, JavaUIMessages.GenerateToStringDialog_customBuilderConfig_typeValidationError); + } + } + + public IStatus validate(Object[] selection) { + return validateBuilderType(((IType)selection[0])); + } + + public IStatus revalidateAll(CustomBuilderSettings builderSettings) { + try { + if (builderSettings.className.length() == 0) { + return new StatusInfo(IStatus.ERROR, JavaUIMessages.GenerateToStringDialog_customBuilderConfig_noBuilderClassError); + } + + IType type= findType(builderSettings.className); + + if (type == null || !type.exists()) { + return new StatusInfo(IStatus.ERROR, MessageFormat.format(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_invalidClassError, + new String[] { builderSettings.className })); + } + + IStatus typeValidation= validateBuilderType(type); + if (!typeValidation.isOK()) + return typeValidation; + + if (!getAppendMethodSuggestions(type).contains(builderSettings.appendMethod)) + return new StatusInfo(IStatus.ERROR, MessageFormat.format(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_invalidAppendMethodError, + new String[] { builderSettings.appendMethod })); + + if (!getResultMethodSuggestions(type).contains(builderSettings.resultMethod)) + return new StatusInfo(IStatus.ERROR, MessageFormat.format(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_invalidResultMethodError, + new String[] { builderSettings.resultMethod })); + + if (!isValidJavaIdentifier(builderSettings.label)) + return new StatusInfo(IStatus.ERROR, MessageFormat.format(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_invalidLabelError, new String[] { builderSettings.label })); + + } catch (JavaModelException e) { + return new StatusInfo(IStatus.WARNING, JavaUIMessages.GenerateToStringDialog_customBuilderConfig_dataBalidationError); + } + return new StatusInfo(); + } + + public IType findType(String builderClassName) throws JavaModelException { + if (fLastValidBuilderType != null && builderClassName.equals(fLastValidBuilderType.getFullyQualifiedParameterizedName())) { + return fLastValidBuilderType; + } + + return fJavaProject.findType(builderClassName, (IProgressMonitor)null); + } + + public List getAppendMethodSuggestions(final IType type) throws JavaModelException { + if (fLastValidBuilderType != null && fLastValidBuilderType.equals(type)) { + return fLastValidAppendMethodSuggestions; + } + return getMethodSuggestions(type, new MethodChecker() { + public boolean isMethodOK(IMethod method) throws JavaModelException { + if (!Flags.isPublic(method.getFlags()) || method.isConstructor()) + return false; + /* To be an append method, it must take exactly one + * Object parameter, and optionally one String parameter. */ + String[] parameterTypes= method.getParameterTypes(); + if (parameterTypes.length == 0 || parameterTypes.length > 2) { + return false; + } + int countObjects= 0, countStrings= 0; + for (int i= 0; i < parameterTypes.length; i++) { + String resolvedParameterTypeName= JavaModelUtil.getResolvedTypeName(parameterTypes[i], type); + if ("java.lang.Object".equals(resolvedParameterTypeName))//$NON-NLS-1$ + countObjects++; + if ("java.lang.String".equals(resolvedParameterTypeName))//$NON-NLS-1$ + countStrings++; + } + return countObjects == 1 && countObjects + countStrings == parameterTypes.length; + + } + }); + } + + public List getResultMethodSuggestions(final IType type) throws JavaModelException { + if (fLastValidBuilderType != null && fLastValidBuilderType.equals(type)) { + return fLastValidResultMethodSuggestions; + } + return getMethodSuggestions(type, new MethodChecker() { + public boolean isMethodOK(IMethod method) throws JavaModelException { + return Flags.isPublic(method.getFlags()) && method.getParameterTypes().length == 0 && "java.lang.String".equals(JavaModelUtil.getResolvedTypeName(method.getReturnType(), type)); //$NON-NLS-1$ + } + }); + } + + private interface MethodChecker { + boolean isMethodOK(IMethod method) throws JavaModelException; + } + + private List getMethodSuggestions(IType type, MethodChecker checker) throws JavaModelException { + ArrayList result= new ArrayList(); + IType[] classes= type.newSupertypeHierarchy(null).getAllClasses(); + for (int i= 0; i < classes.length; i++) { + IMethod[] methods= classes[i].getMethods(); + for (int j= 0; j < methods.length; j++) { + if (checker.isMethodOK(methods[j])) { + String name= methods[j].getElementName(); + if (!result.contains(name)) + result.add(name); + } + } + } + return result; + } + + private boolean isValidJavaIdentifier(String identifier) { + + if (identifier.length() == 0 || !Character.isJavaIdentifierStart(identifier.charAt(0))) { + return false; + } + for (int i= 1; i < identifier.length(); i++) { + if (!Character.isJavaIdentifierPart(identifier.charAt(i))) { + return false; + } + } + return !fJavaKeyWords.contains(identifier); + } + } + + private class CustomBuilderConfigurationDialog extends StatusDialog { + + private final int APPLY_BUTTON= IDialogConstants.CLIENT_ID + 1; + + /** + * Extension for class selection dialog - validates selected type + */ + private final TypeSelectionExtension fExtension= new TypeSelectionExtension() { + public ISelectionStatusValidator getSelectionValidator() { + return getValidator(); + } + }; + + /** + * Listener for text fields - updates combos and validates entered data + */ + private final ModifyListener modifyListener= new ModifyListener() { + + public void modifyText(ModifyEvent e) { + if (e.widget == fBuilderClassName) { + fBuilderSettings.className= fBuilderClassName.getText(); + updateCombos(); + } else if (e.widget == fBuilderLabel) + fBuilderSettings.label= fBuilderLabel.getText(); + + IStatus status= getValidator().revalidateAll(fBuilderSettings); + updateStatus(status); + + enableApplyButton(); + } + }; + + private final CustomBuilderValidator fValidator= new CustomBuilderValidator(getType().getJavaProject()); + + private Text fBuilderClassName; + + private Text fBuilderLabel; + + private Combo fAppendMethodName; + + private Combo fResultMethodName; + + private Button fChainInvocations; + + private ToStringGenerationSettings.CustomBuilderSettings fBuilderSettings; + + private boolean somethingChanged= false; + + public CustomBuilderConfigurationDialog(Shell parent) { + super(parent); + this.setShellStyle(this.getShellStyle() | SWT.RESIZE); + this.setHelpAvailable(false); + fBuilderSettings= getGenerationSettings().getCustomBuilderSettings(); + + } + + public CustomBuilderValidator getValidator() { + return fValidator; + } + + protected Control createDialogArea(Composite parent) { + getShell().setText(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_windowTitle); + + Composite composite= (Composite)super.createDialogArea(parent); + ((GridLayout)composite.getLayout()).numColumns= 3; + LayoutUtil.setWidthHint(composite, convertWidthInCharsToPixels(100)); + + Label label= new Label(composite, SWT.LEFT); + label.setText(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_builderClassField); + fBuilderClassName= createTextField(composite, 1, fBuilderSettings.className); + + Button button= new Button(composite, SWT.NONE); + button.setText(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_browseButton); + setButtonLayoutData(button); + button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + browseForBuilderClass(); + } + }); + + label= new Label(composite, SWT.LEFT); + label.setText(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_labelField); + fBuilderLabel= createTextField(composite, 2, fBuilderSettings.label); + + label= new Label(composite, SWT.LEFT); + label.setText(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_appendMethodField); + fAppendMethodName= new Combo(composite, SWT.READ_ONLY); + fAppendMethodName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + + label= new Label(composite, SWT.LEFT); + label.setText(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_resultMethodField); + fResultMethodName= new Combo(composite, SWT.READ_ONLY); + fResultMethodName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + + updateCombos(); + ModifyListener comboListener= new ModifyListener() { + public void modifyText(ModifyEvent e) { + Combo c= (Combo)e.widget; + if (c.getText().length() > 0) { + if (c == fAppendMethodName) + fBuilderSettings.appendMethod= c.getText(); + if (c == fResultMethodName) + fBuilderSettings.resultMethod= c.getText(); + } + updateStatus(fValidator.revalidateAll(fBuilderSettings)); + enableApplyButton(); + } + }; + fAppendMethodName.addModifyListener(comboListener); + fResultMethodName.addModifyListener(comboListener); + if (!select(fAppendMethodName, fBuilderSettings.appendMethod)) { + fAppendMethodName.select(0); + } + if (!select(fResultMethodName, fBuilderSettings.resultMethod)) { + fResultMethodName.select(0); + } + + fChainInvocations= new Button(composite, SWT.CHECK); + fChainInvocations.setText(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_chainedCallsCheckbox); + fChainInvocations.setSelection(fBuilderSettings.chainCalls); + fChainInvocations.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1)); + fChainInvocations.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + fBuilderSettings.chainCalls= fChainInvocations.getSelection(); + enableApplyButton(); + } + }); + + return composite; + } + + public void create() { + super.create(); + IStatus status= getValidator().revalidateAll(fBuilderSettings); + updateStatus(status); + } + + protected void createButtonsForButtonBar(Composite parent) { + super.createButtonsForButtonBar(parent); + createButton(parent, APPLY_BUTTON, JavaUIMessages.GenerateToStringDialog_customBuilderConfig_applyButton, false).setEnabled(false); + } + + private void enableApplyButton() { + somethingChanged= true; + try { + getButton(APPLY_BUTTON).setEnabled(!getStatus().matches(IStatus.ERROR)); + } catch (NullPointerException e) { + //$FALL-THROUGH$ + } + } + + protected void updateButtonsEnableState(IStatus status) { + super.updateButtonsEnableState(status); + getButton(APPLY_BUTTON).setEnabled(!status.matches(IStatus.ERROR) && somethingChanged); + } + + protected void buttonPressed(int buttonId) { + switch (buttonId) { + case APPLY_BUTTON: + getButton(APPLY_BUTTON).setEnabled(false); + somethingChanged= false; + //$FALL-THROUGH$ + case OK: + applyChanges(); + } + super.buttonPressed(buttonId); + } + + private boolean select(Combo combo, String item) { + int index= Arrays.asList(combo.getItems()).indexOf(item); + if (index >= 0) { + combo.select(index); + return true; + } + return false; + } + + private void updateCombos() { + final String[] empty= new String[0]; + try { + IType type= fValidator.findType(fBuilderSettings.className); + fAppendMethodName.setItems((String[])fValidator.getAppendMethodSuggestions(type).toArray(empty)); + select(fAppendMethodName, fBuilderSettings.appendMethod); + fResultMethodName.setItems((String[])fValidator.getResultMethodSuggestions(type).toArray(empty)); + select(fResultMethodName, fBuilderSettings.resultMethod); + } catch (JavaModelException e1) { + fAppendMethodName.setItems(empty); + fResultMethodName.setItems(empty); + } catch (NullPointerException e1) { + fAppendMethodName.setItems(empty); + fResultMethodName.setItems(empty); + } + } + + private void applyChanges() { + fBuilderSettings.appendMethod= fAppendMethodName.getText(); + fBuilderSettings.resultMethod= fResultMethodName.getText(); + getGenerationSettings().writeCustomBuilderSettings(fBuilderSettings); + } + + private Text createTextField(Composite composite, int gridHSpan, String text) { + Text result= new Text(composite, SWT.BORDER); + result.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, gridHSpan, 1)); + result.setText(text); + result.addModifyListener(modifyListener); + TextFieldNavigationHandler.install(result); + return result; + } + + private void browseForBuilderClass() { + try { + IJavaSearchScope scope= SearchEngine.createJavaSearchScope(new IJavaElement[] { getType().getJavaProject() }); + SelectionDialog dialog= JavaUI.createTypeDialog(getShell(), PlatformUI.getWorkbench().getProgressService(), scope, + IJavaElementSearchConstants.CONSIDER_CLASSES, false, "*ToString", fExtension); //$NON-NLS-1$ + dialog.setTitle(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_classSelection_windowTitle); + dialog.setMessage(JavaUIMessages.GenerateToStringDialog_customBuilderConfig_classSelection_message); + dialog.open(); + if (dialog.getReturnCode() == OK) { + IType type= (IType)dialog.getResult()[0]; + fBuilderClassName.setText(type.getFullyQualifiedParameterizedName()); + List suggestions= fValidator.getAppendMethodSuggestions(type); + if (!suggestions.contains(fAppendMethodName.getText())) + fAppendMethodName.setText((String)suggestions.get(0)); + suggestions= fValidator.getResultMethodSuggestions(type); + if (!suggestions.contains(fResultMethodName.getText())) + fResultMethodName.setText((String)suggestions.get(0)); + } + } catch (JavaModelException e) { + throw new RuntimeException(e); + } + } + } + private ToStringGenerationSettings fGenerationSettings; private static final int DOWN_BUTTON= IDialogConstants.CLIENT_ID + 2; @@ -750,7 +1207,7 @@ * {@inheritDoc} */ public boolean close() { - fGenerationSettings.writeDialogSettings(getDialogSettings()); + fGenerationSettings.writeDialogSettings(); fGenerationSettings.stringFormatTemplate= getTemplates(getDialogSettings())[fGenerationSettings.stringFormatTemplateNumber]; @@ -881,6 +1338,8 @@ private Button skipNullsButton; + private Button styleButton; + protected Composite createCommentSelection(Composite parentComposite) { Composite composite= super.createCommentSelection(parentComposite); @@ -889,8 +1348,8 @@ GridLayout groupLayout= new GridLayout(); group.setLayout(groupLayout); group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - - + + Composite composite2= new Composite(group, SWT.NONE); GridLayout layout= new GridLayout(3, false); layout.marginWidth= 0; @@ -927,9 +1386,9 @@ styleLabel.setText(JavaUIMessages.GenerateToStringDialog_code_style_combo); gridData= new GridData(SWT.FILL, SWT.CENTER, false, false); styleLabel.setLayoutData(gridData); - + final Combo styleCombo= new Combo(composite2, SWT.READ_ONLY); - styleCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + styleCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); styleCombo.setItems(GenerateToStringOperation.getStyleNames()); styleCombo.select(Math.min(fGenerationSettings.toStringStyle, styleCombo.getItemCount() - 1)); SWTUtil.setDefaultVisibleItemCount(styleCombo); @@ -939,6 +1398,15 @@ } }); + styleButton= new Button(composite2, SWT.NONE); + styleButton.setText(JavaUIMessages.GenerateToStringDialog_codeStyleConfigureButton); + setButtonLayoutData(styleButton); + styleButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + configureStyleButtonSelected(); + } + }); + skipNullsButton= new Button(group, SWT.CHECK); skipNullsButton.setText(JavaUIMessages.GenerateToStringDialog_skip_null_button); skipNullsButton.setSelection(fGenerationSettings.skipNulls); @@ -994,13 +1462,20 @@ formatCombo.select(Math.min(fGenerationSettings.stringFormatTemplateNumber, formatCombo.getItemCount() - 1)); } + private void configureStyleButtonSelected() { + CustomBuilderConfigurationDialog dialog= new CustomBuilderConfigurationDialog(getShell()); + dialog.open(); + updateOKStatus(); + } + private void changeToStringStyle(int style) { fGenerationSettings.toStringStyle= style; skipNullsButton.setEnabled(style != GenerateToStringOperation.STRING_FORMAT); - boolean enableFormat= style != GenerateToStringOperation.APACHE_BUILDER && style != GenerateToStringOperation.APACHE_BUILDER_CHAINED && style != GenerateToStringOperation.SPRING_CREATOR - && style != GenerateToStringOperation.SPRING_CREATOR_CHAINED; + boolean enableFormat= (style != GenerateToStringOperation.CUSTOM_BUILDER); formatLabel.setEnabled(enableFormat); formatCombo.setEnabled(enableFormat); + styleButton.setEnabled(style == GenerateToStringOperation.CUSTOM_BUILDER); + updateOKStatus(); } } Index: ui/org/eclipse/jdt/internal/ui/JavaUIMessages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaUIMessages.java,v retrieving revision 1.50 diff -u -r1.50 JavaUIMessages.java --- ui/org/eclipse/jdt/internal/ui/JavaUIMessages.java 30 Mar 2009 13:03:56 -0000 1.50 +++ ui/org/eclipse/jdt/internal/ui/JavaUIMessages.java 17 Apr 2009 14:18:19 -0000 @@ -9,6 +9,7 @@ * IBM Corporation - initial API and implementation * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 * Mateusz Matela - [toString] Template edit dialog has usability issues - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267916 + * Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 *******************************************************************************/ package org.eclipse.jdt.internal.ui; @@ -91,6 +92,7 @@ public static String GenerateToStringDialog_defaultTemplateName; public static String GenerateToStringDialog_dialog_title; public static String GenerateToStringDialog_select_fields_to_include; + public static String GenerateToStringDialog_selectioninfo_customBuilderConfigError; public static String GenerateToStringDialog_selectioninfo_more; public static String GenerateToStringDialog_methods_node; public static String GenerateToStringDialog_fields_node; @@ -99,6 +101,27 @@ public static String GenerateToStringDialog_string_format_combo; public static String GenerateToStringDialog_manage_templates_button; public static String GenerateToStringDialog_code_style_combo; + public static String GenerateToStringDialog_codeStyleConfigureButton; + public static String GenerateToStringDialog_customBuilderConfig_appendMethodField; + public static String GenerateToStringDialog_customBuilderConfig_applyButton; + public static String GenerateToStringDialog_customBuilderConfig_browseButton; + public static String GenerateToStringDialog_customBuilderConfig_builderClassField; + public static String GenerateToStringDialog_customBuilderConfig_chainedCallsCheckbox; + public static String GenerateToStringDialog_customBuilderConfig_classSelection_message; + public static String GenerateToStringDialog_customBuilderConfig_classSelection_windowTitle; + public static String GenerateToStringDialog_customBuilderConfig_dataBalidationError; + public static String GenerateToStringDialog_customBuilderConfig_invalidAppendMethodError; + public static String GenerateToStringDialog_customBuilderConfig_invalidClassError; + public static String GenerateToStringDialog_customBuilderConfig_invalidLabelError; + public static String GenerateToStringDialog_customBuilderConfig_invalidResultMethodError; + public static String GenerateToStringDialog_customBuilderConfig_labelField; + public static String GenerateToStringDialog_customBuilderConfig_noAppendMethodError; + public static String GenerateToStringDialog_customBuilderConfig_noBuilderClassError; + public static String GenerateToStringDialog_customBuilderConfig_noConstructorError; + public static String GenerateToStringDialog_customBuilderConfig_noResultMethodError; + public static String GenerateToStringDialog_customBuilderConfig_resultMethodField; + public static String GenerateToStringDialog_customBuilderConfig_typeValidationError; + public static String GenerateToStringDialog_customBuilderConfig_windowTitle; public static String GenerateToStringDialog_ignore_default_button; public static String GenerateToStringDialog_limit_elements_button; public static String GenerateToStringDialog_newTemplateName; Index: ui/org/eclipse/jdt/internal/ui/JavaUIMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaUIMessages.properties,v retrieving revision 1.284 diff -u -r1.284 JavaUIMessages.properties --- ui/org/eclipse/jdt/internal/ui/JavaUIMessages.properties 30 Mar 2009 13:03:56 -0000 1.284 +++ ui/org/eclipse/jdt/internal/ui/JavaUIMessages.properties 17 Apr 2009 14:18:20 -0000 @@ -9,6 +9,7 @@ # IBM Corporation - initial API and implementation # Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 # Mateusz Matela - [toString] Template edit dialog has usability issues - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267916 +# Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 ############################################################################### JavaPlugin_additionalInfo_affordance=Press 'Tab' from proposal table or click for focus @@ -85,6 +86,7 @@ GenerateToStringDialog_templateEdition_WindowTitle=Edit template GenerateToStringDialog_templateManagerApplyButton=&Apply GenerateToStringDialog_templateManagerNoTemplateErrorMessage=There must be at least one template. +GenerateToStringDialog_selectioninfo_customBuilderConfigError=Custom toString() builder is not configured properly. GenerateToStringDialog_selectioninfo_more={0} of {1} fields and {2} of {3} methods selected. GenerateToStringDialog_methods_node=Methods GenerateToStringDialog_fields_node=Fields @@ -93,6 +95,27 @@ GenerateToStringDialog_string_format_combo=String &format: GenerateToStringDialog_manage_templates_button=&Edit... GenerateToStringDialog_code_style_combo=C&ode style: +GenerateToStringDialog_codeStyleConfigureButton=Con&figure... +GenerateToStringDialog_customBuilderConfig_appendMethodField=&Append method: +GenerateToStringDialog_customBuilderConfig_applyButton=A&pply +GenerateToStringDialog_customBuilderConfig_browseButton=Bro&wse... +GenerateToStringDialog_customBuilderConfig_builderClassField=&Builder class: +GenerateToStringDialog_customBuilderConfig_chainedCallsCheckbox=&Chain invocations +GenerateToStringDialog_customBuilderConfig_classSelection_message=Choose the toString() builder class: +GenerateToStringDialog_customBuilderConfig_classSelection_windowTitle=Builder Class Selection +GenerateToStringDialog_customBuilderConfig_dataBalidationError=Error while walidating entered data +GenerateToStringDialog_customBuilderConfig_invalidAppendMethodError=There are no methods named "{0}" that can be used as append methods in selected class. +GenerateToStringDialog_customBuilderConfig_invalidClassError="{0}" class does not exist. Configuration is invalid. +GenerateToStringDialog_customBuilderConfig_invalidLabelError="{0}" cannot be used as a label for toString() builder. +GenerateToStringDialog_customBuilderConfig_invalidResultMethodError=There''s no method named "{0}" that can be used as a result method in selected class. +GenerateToStringDialog_customBuilderConfig_labelField=Builder &label: +GenerateToStringDialog_customBuilderConfig_noAppendMethodError=Selected type must provide methods that can be used to append objects (e.g. a method taking a signle Object argument). +GenerateToStringDialog_customBuilderConfig_noBuilderClassError=Builder class field shouldn't be empty. Configuration is invalid. +GenerateToStringDialog_customBuilderConfig_noConstructorError=Selected type must provide a constructor that takes a single object. +GenerateToStringDialog_customBuilderConfig_noResultMethodError=Selected type must provide a method that can be used to retrieve result (i.e. taking no arguments and returning String) +GenerateToStringDialog_customBuilderConfig_resultMethodField=&Result method: +GenerateToStringDialog_customBuilderConfig_typeValidationError=Could not validate selected type. +GenerateToStringDialog_customBuilderConfig_windowTitle=Configure Custom toString() Builder GenerateToStringDialog_ignore_default_button=&List contents of arrays instead of using native toString() GenerateToStringDialog_limit_elements_button=Li&mit number of items in arrays/collections/maps to GenerateToStringDialog_skip_null_button=Skip &null values Index: core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/CustomBuilderGenerator.java =================================================================== RCS file: core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/CustomBuilderGenerator.java diff -N core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/CustomBuilderGenerator.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core extension/org/eclipse/jdt/internal/corext/codemanipulation/tostringgeneration/CustomBuilderGenerator.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,300 @@ +/******************************************************************************* + * Copyright (c) 2008 Mateusz Matela and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070 + * Mateusz Matela - [toString] finish toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=267710 + *******************************************************************************/ +package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.ltk.core.refactoring.RefactoringStatus; + +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.NamingConventions; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.InfixExpression.Operator; + +import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationMessages; +import org.eclipse.jdt.internal.corext.util.JavaModelUtil; + + +/** + *

+ * Implementation of AbstractToStringGenerator that creates toString() + * method using external library. The library must deliver a string builder , that is a class that + * fulfills following requirements: + *

    + *
  • Provides a constructor taking single Object
  • + *
  • Provides methods for appending objects. There may many such methods (with the same name, for + * example append(...)), but there must be at least a version that takes single Object + * or an Object and a String (in any order). These methods should return builder object, otherwise + * generator will not be able to make call chains.
  • + *
  • Provides a result method (usually toString()), that is a method that takes no + * arguments and returns a Strinig
  • + *
+ *

+ *

+ * Generated methods look like this: + * + *

+ * public String toString() {
+ * 	ExternalBuilder builder= new ExternalBuilder();
+ * 	builder.append("field1", field1);
+ * 	builder.append("field2", field2);
+ * 	return builder.toString();
+ * }
+ * 
+ * + *

+ * + * @since 3.5 + */ +public class CustomBuilderGenerator extends AbstractToStringGenerator { + + private final List primitiveTypes= Arrays.asList(new String[] { "byte", "short", "char", "int", "long", "float", "double", "boolean" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ + + private final String[] wrapperTypes= new String[] { "java.lang.Byte", "java.lang.Short", "java.lang.Character", "java.lang.Integer", "java.lang.Long", "java.lang.Float", "java.lang.Double", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ + "java.lang.Boolean" }; //$NON-NLS-1$ + + /** + * true, if the last expression created with {@link #createAppendMethodForMember(Object)} + * returns builder type and therefore can be used to chain calls + **/ + private boolean canChainLastAppendCall; + + /** + * Class for storing information about versions of append method in the builder class that can + * be used for different member types + */ + private class AppendMethodInformation { + /** + * Type of method in raltion to taken parameter types. Possible values: + *
    + *
  1. method takes one type parameter
  2. + *
  3. method takes one type parameter and one string
  4. + *
  5. method takes one string and one type parameter
  6. + *
+ */ + public int methodType; + + /** + * true if method returns the builder class object so it can be used to form chains of calls + **/ + public boolean returnsBuilder; + } + + /** + * Information about versions of append method in the builder type + * + * key: String - fully qualified name of a member type + * + * value: {@link AppendMethodInformation} - information about corresponding method + */ + private HashMap appendMethodSpecificTypes= new HashMap(); + + public RefactoringStatus checkConditions() { + RefactoringStatus status= super.checkConditions(); + if (fContext.isCustomArray() || fContext.isLimitItems()) + status.addWarning(CodeGenerationMessages.GenerateToStringOperation_warning_no_arrays_collections_with_this_style); + return status; + } + + protected void addElement(Object element) { + } + + protected void initialize() { + super.initialize(); + + fillAppendMethodsMap(); + + tidyAppendsMethodsMap(); + } + + public MethodDeclaration generateToStringMethod() throws CoreException { + initialize(); + + //ToStringBuilder builder= new ToStringBuilder(this); + String builderVariableName= createNameSuggestion(getContext().getCustomBuilderLabel(), NamingConventions.VK_LOCAL); + VariableDeclarationFragment fragment= fAst.newVariableDeclarationFragment(); + fragment.setName(fAst.newSimpleName(builderVariableName)); + ClassInstanceCreation classInstance= fAst.newClassInstanceCreation(); + String typeName= addImport(getContext().getCustomBuilderClass()); + classInstance.setType(fAst.newSimpleType(fAst.newSimpleName(typeName))); + classInstance.arguments().add(fAst.newThisExpression()); + fragment.setInitializer(classInstance); + VariableDeclarationStatement vStatement= fAst.newVariableDeclarationStatement(fragment); + vStatement.setType(fAst.newSimpleType(fAst.newName(typeName))); + toStringMethod.getBody().statements().add(vStatement); + + /* expression for accumulating chained calls */ + Expression expression= null; + + for (int i= 0; i < getContext().getSelectedMembers().length; i++) { + //builder.append("member", member); + MethodInvocation appendInvocation= createAppendMethodForMember(getContext().getSelectedMembers()[i]); + if (getContext().isSkipNulls() && !getMemberType(getContext().getSelectedMembers()[i]).isPrimitive()) { + if (expression != null) { + toStringMethod.getBody().statements().add(fAst.newExpressionStatement(expression)); + expression= null; + } + appendInvocation.setExpression(fAst.newSimpleName(builderVariableName)); + IfStatement ifStatement= fAst.newIfStatement(); + ifStatement.setExpression(createInfixExpression(createMemberAccessExpression(getContext().getSelectedMembers()[i], true, true), Operator.NOT_EQUALS, fAst.newNullLiteral())); + ifStatement.setThenStatement(createOneStatementBlock(appendInvocation)); + toStringMethod.getBody().statements().add(ifStatement); + } else { + if (expression != null) { + appendInvocation.setExpression(expression); + } else { + appendInvocation.setExpression(fAst.newSimpleName(builderVariableName)); + } + if (getContext().isCustomBuilderChainedCalls() && canChainLastAppendCall) { + expression= appendInvocation; + } else { + expression= null; + toStringMethod.getBody().statements().add(fAst.newExpressionStatement(appendInvocation)); + } + } + } + + if (expression != null) { + toStringMethod.getBody().statements().add(fAst.newExpressionStatement(expression)); + } + // return builder.toString(); + ReturnStatement rStatement= fAst.newReturnStatement(); + rStatement.setExpression(createMethodInvocation(builderVariableName, getContext().getCustomBuilderResultMethod(), null)); + toStringMethod.getBody().statements().add(rStatement); + + complete(); + + return toStringMethod; + } + + /** + * Searches through methods with proper name and for each argument type + * remembers the best option + */ + private void fillAppendMethodsMap() { + try { + IJavaProject javaProject= getContext().getTypeBinding().getJavaElement().getJavaProject(); + IType type= javaProject.findType(getContext().getCustomBuilderClass()); + IType[] types= type.newSupertypeHierarchy(null).getAllClasses(); + for (int i= 0; i < types.length; i++) { + IMethod[] methods= types[i].getMethods(); + for (int j= 0; j < methods.length; j++) { + if (!Flags.isPublic(methods[j].getFlags()) || !methods[j].getElementName().equals(getContext().getCustomBuilderAppendMethod())) + continue; + String[] parameterTypes= methods[j].getParameterTypes(); + AppendMethodInformation appendMethodInformation= new AppendMethodInformation(); + String specyficType; + if (parameterTypes.length == 1) { + specyficType= JavaModelUtil.getResolvedTypeName(parameterTypes[0], types[i]); + appendMethodInformation.methodType= 1; + } else if (parameterTypes.length == 2) { + String resolvedParameterTypeName1= JavaModelUtil.getResolvedTypeName(parameterTypes[0], types[i]); + String resolvedParameterTypeName2= JavaModelUtil.getResolvedTypeName(parameterTypes[1], types[i]); + if (resolvedParameterTypeName1.equals("java.lang.String")) {//$NON-NLS-1$ + specyficType= resolvedParameterTypeName2; + appendMethodInformation.methodType= 3; + } else if (resolvedParameterTypeName2.equals("java.lang.String")) {//$NON-NLS-1$ + specyficType= resolvedParameterTypeName1; + appendMethodInformation.methodType= 2; + } else + continue; + } else + continue; + + appendMethodInformation.returnsBuilder= getContext().getCustomBuilderClass().equals(JavaModelUtil.getResolvedTypeName(methods[j].getReturnType(), types[i])); + + AppendMethodInformation oldAMI= (AppendMethodInformation)appendMethodSpecificTypes.get(specyficType); + if (oldAMI == null || oldAMI.methodType < appendMethodInformation.methodType) { + appendMethodSpecificTypes.put(specyficType, appendMethodInformation); + } + } + } + } catch (JavaModelException e) { + throw new RuntimeException("couldn't initialize custom toString() builder generator", e); //$NON-NLS-1$ + } + } + + /** + * Removes information about types from {@link #appendMethodSpecificTypes} if their + * parametersType is worse than for java.lang.Object. + */ + private void tidyAppendsMethodsMap() { + int objectParametersType= ((AppendMethodInformation)appendMethodSpecificTypes.get("java.lang.Object")).methodType; //$NON-NLS-1$ + Set entrySet= appendMethodSpecificTypes.entrySet(); + for (Iterator iterator= entrySet.iterator(); iterator.hasNext();) { + Map.Entry entry= (Map.Entry)iterator.next(); + if (((AppendMethodInformation)entry.getValue()).methodType < objectParametersType) { + iterator.remove(); + } + } + } + + private MethodInvocation createAppendMethodForMember(Object member) { + ITypeBinding memberType= getMemberType(member); + String memberTypeName= memberType.getQualifiedName(); + + Expression memberAccessExpression= null; + + AppendMethodInformation ami= (AppendMethodInformation)appendMethodSpecificTypes.get(memberTypeName); + if (ami == null) { + ami= (AppendMethodInformation)appendMethodSpecificTypes.get("java.lang.Object");//$NON-NLS-1$ + if (memberType.isPrimitive() && !getContext().is50orHigher()) { + String nonPrimitiveType= wrapperTypes[primitiveTypes.indexOf(memberTypeName)]; + ClassInstanceCreation classInstance= fAst.newClassInstanceCreation(); + classInstance.setType(fAst.newSimpleType(fAst.newSimpleName(addImport(nonPrimitiveType)))); + classInstance.arguments().add(createMemberAccessExpression(member, true, true)); + memberAccessExpression= classInstance; + } + } + if (memberAccessExpression == null) { + memberAccessExpression= createMemberAccessExpression(member, false, getContext().isSkipNulls()); + } + + MethodInvocation appendInvocation= fAst.newMethodInvocation(); + appendInvocation.setName(fAst.newSimpleName(getContext().getCustomBuilderAppendMethod())); + if (ami.methodType == 1 || ami.methodType == 2) { + appendInvocation.arguments().add(memberAccessExpression); + } + if (ami.methodType == 2 || ami.methodType == 3) { + StringLiteral literal= fAst.newStringLiteral(); + literal.setLiteralValue(getMemberName(member, ToStringTemplateParser.MEMBER_NAME_PARENTHESIS_VARIABLE)); + appendInvocation.arguments().add(literal); + } + if (ami.methodType == 3) { + appendInvocation.arguments().add(memberAccessExpression); + } + + canChainLastAppendCall= ami.returnsBuilder; + + return appendInvocation; + } +}