View Javadoc

1   /*
2    * Copyright (c) 2001-2003 The XDoclet team
3    * All rights reserved.
4    */
5   package xjavadoc;
6   
7   import java.lang.reflect.Modifier;
8   import java.util.ArrayList;
9   import java.util.Iterator;
10  import java.util.List;
11  import java.beans.Introspector;
12  
13  /***
14   * Describe what this class does
15   *
16   * @author    Aslak Hellesøy
17   * @created   25. februar 2003
18   */
19  final class MethodImpl extends AbstractExecutableMember implements XMethod
20  {
21  	public static int  instanceCount = 0;
22  
23  	private String     methodNameWithSignatureAndModifiers = null;
24  	private String     methodNameWithSignatureWithoutModifiers = null;
25  
26  	private ReturnType _returnType = new ReturnType( this );
27  
28  	public MethodImpl( AbstractClass containingClass, XTagFactory tagFactory )
29  	{
30  		super( containingClass, tagFactory );
31  
32  		// if we're in an interface, add public modifier even if it isn't declared,
33  		// since interface methods are always public.
34  		if( containingClass.isInterface() )
35  		{
36  			addModifier( Modifier.PUBLIC );
37  		}
38  		instanceCount++;
39  	}
40  
41  	/***
42  	 * Gets the Constructor attribute of the SourceMethod object
43  	 *
44  	 * @return   The Constructor value
45  	 */
46  	public final boolean isConstructor()
47  	{
48  		return false;
49  	}
50  
51  	public final Type getReturnType()
52  	{
53  		return _returnType;
54  	}
55  
56  	public XProgramElement getSuperElement()
57  	{
58  		return getSuperElement( true );
59  	}
60  
61  	public List getSuperInterfaceElements()
62  	{
63  
64  		Iterator interfaces = getContainingClass().getInterfaces().iterator();
65  
66  		List result = new ArrayList();
67  
68  		while ( interfaces.hasNext() )
69  		{
70  
71  			XClass superinterface = (XClass) interfaces.next();
72  
73  			XExecutableMember superExecutableMember = superinterface.getMethod( getNameWithSignature( false ) );
74  			if( superExecutableMember != null )
75  			{
76  				result.add( superExecutableMember );
77  			}
78  
79  			//TODO: do we need to keep searching upwards, to find superinterfaces?
80  
81  		}
82  
83  		return result;
84  	}
85  
86  	public XMethod getAccessor()
87  	{
88  		XMethod result = null;
89  
90  		if( isPropertyMutator() )
91  		{
92  			Type requiredType = ( Type ) getParameters().iterator().next();
93  			String getterNameWithSignature = "get" + getNameWithoutPrefix() + "()";
94  			String isserNameWithSignature = "is" + getNameWithoutPrefix() + "()";
95  			XMethod getter = getContainingClass().getMethod( getterNameWithSignature, true );
96  			XMethod isser = getContainingClass().getMethod( isserNameWithSignature, true );
97  
98  			// If only one is non null, return it. If both or none exist, return null.
99  			if( getter == null && isser != null )
100 			{
101 				result = isser;
102 			}
103 			else if( getter != null && isser == null )
104 			{
105 				result = getter;
106 			}
107 			// Verify that the types are compatible
108 			if( !requiredType.equals( result.getReturnType() ) )
109 			{
110 				result = null;
111 			}
112 		}
113 		return result;
114 	}
115 
116 	public XMethod getMutator()
117 	{
118 		XMethod result = null;
119 
120 		if( isPropertyAccessor() )
121 		{
122 			Type requiredType = getReturnType();
123 			String argument = requiredType.getType().getQualifiedName() + requiredType.getDimensionAsString();
124 			String setterNameWithSignature = "set" + getNameWithoutPrefix() + "(" + argument + ")";
125 
126 			result = getContainingClass().getMethod( setterNameWithSignature, true );
127 		}
128 		return result;
129 	}
130 
131 	public boolean isPropertyAccessor()
132 	{
133 		boolean signatureOk = false;
134 		boolean nameOk = false;
135 
136 		if( getName().startsWith( "is" ) )
137 		{
138 			signatureOk = getReturnType().getType().getQualifiedName().equals( "boolean" ) || getReturnType().getType().getQualifiedName().equals( "java.lang.Boolean" );
139 			signatureOk = signatureOk && getReturnType().getDimension() == 0;
140 			if( getName().length() > 2 )
141 			{
142 				nameOk = Character.isUpperCase( getName().charAt( 2 ) );
143 			}
144 		}
145 		if( getName().startsWith( "get" ) )
146 		{
147 			signatureOk = true;
148 			if( getName().length() > 3 )
149 			{
150 				nameOk = Character.isUpperCase( getName().charAt( 3 ) );
151 			}
152 		}
153 
154 		boolean noParams = getParameters().size() == 0;
155 
156 		return signatureOk && nameOk && noParams;
157 	}
158 
159 	public boolean isPropertyMutator()
160 	{
161 		boolean nameOk = false;
162 
163 		if( getName().startsWith( "set" ) )
164 		{
165 			if( getName().length() > 3 )
166 			{
167 				nameOk = Character.isUpperCase( getName().charAt( 3 ) );
168 			}
169 		}
170 
171 		boolean oneParam = getParameters().size() == 1;
172 
173 		return nameOk && oneParam;
174 	}
175 
176 	public String getPropertyName()
177 	{
178 		String result = null;
179 
180 		if( getName().startsWith( "get" ) || getName().startsWith( "set" ) )
181 		{
182 			result = Introspector.decapitalize( getName().substring( 3 ) );
183 		}
184 		else if( getName().startsWith( "is" ) )
185 		{
186 			result = Introspector.decapitalize( getName().substring( 2 ) );
187 		}
188 		return result;
189 	}
190 
191 	public Type getPropertyType()
192 	{
193 		Type result = null;
194 
195 		if( isPropertyMutator() )
196 		{
197 			XParameter parameter = ( XParameter ) getParameters().iterator().next();
198 
199 			result = parameter;
200 		}
201 		else if( isPropertyAccessor() )
202 		{
203 			result = getReturnType();
204 		}
205 		return result;
206 	}
207 
208 	public String getNameWithoutPrefix()
209 	{
210 		for( int i = 0; i < getName().length(); i++ )
211 		{
212 			if( Character.isUpperCase( getName().charAt( i ) ) )
213 			{
214 				return getName().substring( i );
215 			}
216 		}
217 		return null;
218 	}
219 
220 	/***
221 	 * Sets the ReturnType attribute of the SourceMethod object
222 	 *
223 	 * @param returnType  The new ReturnType value
224 	 */
225 	public final void setReturnType( String returnType )
226 	{
227 		_returnType.setType( returnType );
228 	}
229 
230 	/***
231 	 * Sets the ReturnDimension attribute of the SourceMethod object
232 	 *
233 	 * @param d  The new ReturnDimension value
234 	 */
235 	public final void setReturnDimension( int d )
236 	{
237 		_returnType.setDimension( d );
238 	}
239 
240 	/***
241 	 * Two methods are equal if they have the same return type, name and signature,
242 	 * regardless of the enclosing class and modifiers. Methods are compared for
243 	 * equality when calling XClass.getMethods(true)
244 	 *
245 	 * @param o
246 	 * @return
247 	 */
248 	public boolean equals( Object o )
249 	{
250 		MethodImpl other = ( MethodImpl ) o;
251 
252 		return getMethodNameWithSignatureWithoutModifiers().equals( other.getMethodNameWithSignatureWithoutModifiers() );
253 	}
254 
255 	public int hashCode()
256 	{
257 		return toString( false ).hashCode();
258 	}
259 
260 	public String toString()
261 	{
262 		return getMethodNameWithSignatureAndModifiers() + " [" + getContainingClass().getQualifiedName() + "]";
263 	}
264 
265 	protected String buildStringId()
266 	{
267 		return getMethodNameWithSignatureWithoutModifiers();
268 	}
269 
270 	private String getMethodNameWithSignatureAndModifiers()
271 	{
272 		if( methodNameWithSignatureAndModifiers == null )
273 		{
274 			methodNameWithSignatureAndModifiers = toString( true );
275 		}
276 		return methodNameWithSignatureAndModifiers;
277 	}
278 
279 	private String getMethodNameWithSignatureWithoutModifiers()
280 	{
281 		if( methodNameWithSignatureWithoutModifiers == null )
282 		{
283 			methodNameWithSignatureWithoutModifiers = toString( false );
284 		}
285 		return methodNameWithSignatureWithoutModifiers;
286 	}
287 
288 	/***
289 	 * Builds a String uniquely describing this method
290 	 *
291 	 * @param modifiers
292 	 * @return           a String uniquely describing this method
293 	 */
294 	private String toString( boolean modifiers )
295 	{
296 		StringBuffer sb;
297 
298 		if( modifiers )
299 		{
300 			sb = new StringBuffer( getModifiers() );
301 			if( sb.length() > 0 )
302 			{
303 				sb.append( ' ' );
304 			}
305 		}
306 		else
307 		{
308 			sb = new StringBuffer();
309 		}
310 		sb.append( getReturnType().getType().getQualifiedName() );
311 		sb.append( getReturnType().getDimensionAsString() );
312 		sb.append( ' ' );
313 		sb.append( getNameWithSignature( false ) );
314 		return sb.toString();
315 	}
316 
317 }