View Javadoc

1   /* ====================================================================
2    *   Copyright 2003-2005 Fabrizio Giustina.
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   * ====================================================================
16   */
17  package net.sf.commonclipse;
18  
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.Map;
22  
23  import org.eclipse.jdt.core.Flags;
24  import org.eclipse.jdt.core.IField;
25  import org.eclipse.jdt.core.IMethod;
26  import org.eclipse.jdt.core.IType;
27  import org.eclipse.jdt.core.ITypeHierarchy;
28  import org.eclipse.jdt.core.JavaModelException;
29  
30  
31  /***
32   * Generator for toString() methods.
33   * @author fgiust
34   * @version $Revision: 1.7 $ ($Author: fgiust $)
35   */
36  public final class ToStringGenerator extends Generator
37  {
38  
39      /***
40       * Class name for the ToString buider.
41       */
42      private static final String BUILDER_CLASS = "org.apache.commons.lang.builder.ToStringBuilder"; //$NON-NLS-1$
43  
44      /***
45       * Singleton for ToStringGenerator.
46       */
47      private static Generator instance = new ToStringGenerator();
48  
49      /***
50       * Use getInstance() to obtain an instance of ToStringGenerator.
51       */
52      private ToStringGenerator()
53      {
54      }
55  
56      /***
57       * Returns the ToStringGenerator instance.
58       * @return instance of ToStringGenerator
59       */
60      public static Generator getInstance()
61      {
62          return instance;
63      }
64  
65      /***
66       * @see net.sf.commonclipse.Generator#getMethodName()
67       */
68      protected String getMethodName()
69      {
70          return "toString"; //$NON-NLS-1$
71      }
72  
73      /***
74       * @see net.sf.commonclipse.Generator#addImports(org.eclipse.jdt.core.IType)
75       */
76      protected void addImports(IType type) throws JavaModelException
77      {
78          type.getCompilationUnit().createImport(BUILDER_CLASS, null, null);
79  
80          if (CCPluginPreferences.getPreferences().useCustomToStringStyle())
81          {
82              type.getCompilationUnit().createImport(
83                  CCPluginPreferences.getPreferences().getToStringStyleQualifiedClass(),
84                  null,
85                  null);
86          }
87      }
88  
89      /***
90       * @see net.sf.commonclipse.Generator#createMethod(org.eclipse.jdt.core.IType)
91       */
92      protected String createMethod(IType type) throws JavaModelException
93      {
94  
95          StringBuffer buffer = new StringBuffer();
96  
97          buffer.append(getJavadoc());
98  
99          buffer.append("    public String toString()\n    {\n        return new ToStringBuilder(this"); //$NON-NLS-1$
100 
101         if (CCPluginPreferences.getPreferences().useCustomToStringStyle())
102         {
103             buffer.append(", "); //$NON-NLS-1$
104             buffer.append(CCPluginPreferences.getPreferences().getToStringStyleClassAndConstant());
105         }
106 
107         buffer.append(")\n"); //$NON-NLS-1$
108 
109         if (CCPluginPreferences.getPreferences().appendSuperToToString())
110         {
111             buffer.append(".appendSuper(super.toString())\n"); //$NON-NLS-1$
112         }
113 
114         if (CCPluginPreferences.getPreferences().useJavabeanToString())
115         {
116             buffer.append(buildAppenderListFromBean(type));
117         }
118         else
119         {
120             buffer.append(buildAppenderList(type));
121         }
122 
123         buffer.append(".toString();\n}"); //$NON-NLS-1$
124 
125         return buffer.toString();
126     }
127 
128     /***
129      * Iterates on javabean properties and calls getFieldAppender for all of them.
130      * @param type IType
131      * @return String
132      * @throws JavaModelException exception in analyzing properties
133      */
134     private String buildAppenderListFromBean(IType type) throws JavaModelException
135     {
136         // temporary map of methods to avoid duplicated entry
137         Map getterMethods = buildMethodsMap(type);
138 
139         // fields to match method names
140         Map fields = buildFieldMap(type);
141 
142         // now iterates on generated method list and create the toString method body
143         Iterator iterator = getterMethods.entrySet().iterator();
144 
145         StringBuffer buffer = new StringBuffer();
146 
147         while (iterator.hasNext())
148         {
149             IMethod method = (IMethod) ((Map.Entry) iterator.next()).getValue();
150             String methodName = method.getElementName();
151             String propertyName = getJavabeanProperyName(methodName);
152 
153             // check if propertyName is excluded
154             if (!isExcluded(propertyName))
155             {
156                 // does a field with the same name exist?
157                 IField matchingField = (IField) fields.get(propertyName);
158 
159                 if (matchingField != null)
160                 {
161                     if (propertyName.equals(matchingField.getElementName()))
162                     {
163                         // if we have a fields with the same name and type of the property, use it instead
164                         // of the getter method for the toString()
165                         buffer.append(getFieldAppender(propertyName, propertyName));
166                         continue;
167                     }
168                 }
169 
170                 // else add the getter method to the toString
171                 buffer.append(getFieldAppender(propertyName, methodName + "()")); //$NON-NLS-1$
172             }
173         }
174         return buffer.toString();
175     }
176 
177     /***
178      * Returns a Map containing all the javabean getter methods in this type and its supertypes.
179      * @param type IType
180      * @return Map containg method names - IMethod objects
181      * @throws JavaModelException exception in analyzing type
182      */
183     private Map buildMethodsMap(IType type) throws JavaModelException
184     {
185         Map getterMethods = new HashMap();
186 
187         // iterates on hierarchy, looking for properties also if defined in superclasses
188         ITypeHierarchy hierarchy = type.newSupertypeHierarchy(null);
189         IType[] types = hierarchy.getAllClasses();
190 
191         for (int j = 0; j < types.length; j++)
192         {
193             IMethod[] superMethods = types[j].getMethods();
194 
195             for (int x = 0; x < superMethods.length; x++)
196             {
197                 IMethod method = superMethods[x];
198 
199                 if (isJavabeanGetter(method))
200                 {
201                     getterMethods.put(method.getElementName(), method);
202                 }
203             }
204         }
205 
206         return getterMethods;
207     }
208 
209     /***
210      * Returns the javabean property name from the getter method name.
211      * @param methodName getter method name
212      * @return javabean property name (ex. "test" for "getTest()")
213      */
214     private String getJavabeanProperyName(String methodName)
215     {
216 
217         String propertyName;
218         if (methodName.startsWith("get")) //$NON-NLS-1$
219         {
220             propertyName = methodName.substring(3, methodName.length());
221         }
222         else
223         {
224             // should be a boolean property isXXX
225             propertyName = methodName.substring(2, methodName.length());
226         }
227 
228         if (propertyName.length() > 1 && Character.isLowerCase(propertyName.charAt(1)))
229         {
230             propertyName = Character.toLowerCase(propertyName.charAt(0))
231                 + propertyName.substring(1, propertyName.length());
232         }
233         else if (propertyName.length() == 1)
234         {
235             propertyName = propertyName.toLowerCase();
236         }
237         return propertyName;
238     }
239 
240     /***
241      * Checks if the given method is a javabean getter (start with get or is for boolean properties, no param).
242      * @param method IMethod
243      * @return <code>true</code> if the method is a javabean property accessor
244      * @throws JavaModelException exception thrown in analyzing method
245      */
246     private boolean isJavabeanGetter(IMethod method) throws JavaModelException
247     {
248 
249         if (method.getNumberOfParameters() == 0 && Flags.isPublic(method.getFlags()))
250         {
251             String methodName = method.getElementName();
252 
253             if (methodName.length() > 3 && methodName.startsWith("get")) //$NON-NLS-1$
254             {
255                 return true;
256             }
257             else if (methodName.length() > 2 && methodName.startsWith("is") //$NON-NLS-1$
258                 && ("Z".equals(method.getReturnType()) //$NON-NLS-1$
259                 || "QBoolean;".equals(method.getReturnType()))) //$NON-NLS-1$
260             {
261                 return true;
262             }
263         }
264         return false;
265     }
266 
267     /***
268      * Generates the method javadoc.
269      * @return String javadoc
270      */
271     private String getJavadoc()
272     {
273         return "/**\n * @see java.lang.Object#toString()\n */\n"; //$NON-NLS-1$
274     }
275 
276     /***
277      * @see net.sf.commonclipse.Generator#getExistingMethod(org.eclipse.jdt.core.IType)
278      */
279     protected IMethod getExistingMethod(IType type)
280     {
281         return type.getMethod(getMethodName(), new String[0]);
282     }
283 
284     /***
285      * @see net.sf.commonclipse.Generator#getFieldAppender(java.lang.String, java.lang.String)
286      */
287     protected String getFieldAppender(String fieldName, String accessor)
288     {
289         return ".append(\"" + fieldName + "\", this." + accessor + ")\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
290     }
291 
292 }