/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.codemodel.internal; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import com.sun.codemodel.internal.util.ClassNameComparator; /** * Java method. */ public class JMethod extends JGenerifiableImpl implements JDeclaration, JAnnotatable { /** * Modifiers for this method */ private JMods mods; /** * Return type for this method */ private JType type = null; /** * Name of this method */ private String name = null; /** * List of parameters for this method's declaration */ private final List<JVar> params = new ArrayList<JVar>(); /** * Set of exceptions that this method may throw. * A set instance lazily created. */ private Set<JClass> _throws; /** * JBlock of statements that makes up the body this method */ private JBlock body = null; private JDefinedClass outer; /** * javadoc comments for this JMethod */ private JDocComment jdoc = null; /** * Variable parameter for this method's varargs declaration * introduced in J2SE 1.5 */ private JVar varParam = null; /** * Annotations on this variable. Lazily created. */ private List<JAnnotationUse> annotations = null; private boolean isConstructor() { return type == null; } /** To set the default value for the * annotation member */ private JExpression defaultValue = null; /** * JMethod constructor * * @param mods * Modifiers for this method's declaration * * @param type * Return type for the method * * @param name * Name of this method */ JMethod(JDefinedClass outer, int mods, JType type, String name) { this.mods = JMods.forMethod(mods); this.type = type; this.name = name; this.outer = outer; } /** * Constructor constructor * * @param mods * Modifiers for this constructor's declaration * * @param _class * JClass containing this constructor */ JMethod(int mods, JDefinedClass _class) { this.mods = JMods.forMethod(mods); this.type = null; this.name = _class.name(); this.outer = _class; } private Set<JClass> getThrows() { if(_throws==null) _throws = new TreeSet<JClass>(ClassNameComparator.theInstance); return _throws; } /** * Add an exception to the list of exceptions that this * method may throw. * * @param exception * Name of an exception that this method may throw */ public JMethod _throws(JClass exception) { getThrows().add(exception); return this; } public JMethod _throws(Class exception) { return _throws(outer.owner().ref(exception)); } /** * Add the specified variable to the list of parameters * for this method signature. * * @param type * JType of the parameter being added * * @param name * Name of the parameter being added * * @return New parameter variable */ public JVar param(int mods, JType type, String name) { JVar v = new JVar(JMods.forVar(mods), type, name, null); params.add(v); return v; } public JVar param(JType type, String name) { return param(JMod.NONE, type, name); } public JVar param(int mods, Class type, String name) { return param(mods, outer.owner()._ref(type), name); } public JVar param(Class type, String name) { return param(outer.owner()._ref(type), name); } /** * @see #varParam(JType, String) */ public JVar varParam(Class type, String name) { return varParam(outer.owner()._ref(type),name); } /** * Add the specified variable argument to the list of parameters * for this method signature. * * @param type * Type of the parameter being added. * * @param name * Name of the parameter being added * * @return the variable parameter * * @throws IllegalStateException * If this method is called twice. * varargs in J2SE 1.5 can appear only once in the * method signature. */ public JVar varParam(JType type, String name) { if (!hasVarArgs()) { varParam = new JVar( JMods.forVar(JMod.NONE), type.array(), name, null); return varParam; } else { throw new IllegalStateException( "Cannot have two varargs in a method,\n" + "Check if varParam method of JMethod is" + " invoked more than once"); } } /** * Adds an annotation to this variable. * @param clazz * The annotation class to annotate the field with */ public JAnnotationUse annotate(JClass clazz){ if(annotations==null) annotations = new ArrayList<JAnnotationUse>(); JAnnotationUse a = new JAnnotationUse(clazz); annotations.add(a); return a; } /** * Adds an annotation to this variable. * * @param clazz * The annotation class to annotate the field with */ public JAnnotationUse annotate(Class <? extends Annotation> clazz){ return annotate(owner().ref(clazz)); } public <W extends JAnnotationWriter> W annotate2(Class<W> clazz) { return TypedAnnotationWriter.create(clazz,this); } /** * Check if there are any varargs declared * for this method signature. */ public boolean hasVarArgs() { return this.varParam!=null; } public String name() { return name; } /** * Changes the name of the method. */ public void name(String n) { this.name = n; } /** * Returns the return type. */ public JType type() { return type; } /** * Overrides the return type. */ public void type(JType t) { this.type = t; } /** * Returns all the parameter types in an array. * @return * If there's no parameter, an empty array will be returned. */ public JType[] listParamTypes() { JType[] r = new JType[params.size()]; for (int i = 0; i < r.length; i++) r[i] = params.get(i).type(); return r; } /** * Returns the varags parameter type. * @return * If there's no vararg parameter type, null will be returned. */ public JType listVarParamType() { if (varParam != null) return varParam.type(); else return null; } /** * Returns all the parameters in an array. * @return * If there's no parameter, an empty array will be returned. */ public JVar[] listParams() { return params.toArray(new JVar[params.size()]); } /** * Returns the variable parameter * @return * If there's no parameter, null will be returned. */ public JVar listVarParam() { return varParam; } /** * Returns true if the method has the specified signature. */ public boolean hasSignature(JType[] argTypes) { JVar[] p = listParams(); if (p.length != argTypes.length) return false; for (int i = 0; i < p.length; i++) if (!p[i].type().equals(argTypes[i])) return false; return true; } /** * Get the block that makes up body of this method * * @return Body of method */ public JBlock body() { if (body == null) body = new JBlock(); return body; } /** * Specify the default value for this annotation member * @param value * Default value for the annotation member * */ public void declareDefaultValue(JExpression value){ this.defaultValue = value; } /** * Creates, if necessary, and returns the class javadoc for this * JDefinedClass * * @return JDocComment containing javadocs for this class */ public JDocComment javadoc() { if (jdoc == null) jdoc = new JDocComment(owner()); return jdoc; } public void declare(JFormatter f) { if (jdoc != null) f.g(jdoc); if (annotations != null){ for (JAnnotationUse a : annotations) f.g(a).nl(); } f.g(mods); // declare the generics parameters super.declare(f); if (!isConstructor()) f.g(type); f.id(name).p('(').i(); // when parameters are printed in new lines, we want them to be indented. // there's a good chance no newlines happen, too, but just in case it does. boolean first = true; for (JVar var : params) { if (!first) f.p(','); if(var.isAnnotated()) f.nl(); f.b(var); first = false; } if (hasVarArgs()) { if (!first) f.p(','); f.g(varParam.type().elementType()); f.p("... "); f.id(varParam.name()); } f.o().p(')'); if (_throws!=null && !_throws.isEmpty()) { f.nl().i().p("throws").g(_throws).nl().o(); } if (defaultValue != null) { f.p("default "); f.g(defaultValue); } if (body != null) { f.s(body); } else if ( !outer.isInterface() && !outer.isAnnotationTypeDeclaration() && !mods.isAbstract() && !mods.isNative()) { // Print an empty body for non-native, non-abstract methods f.s(new JBlock()); } else { f.p(';').nl(); } } /** * @return * the current modifiers of this method. * Always return non-null valid object. */ public JMods mods() { return mods; } /** * @deprecated use {@link #mods()} */ public JMods getMods() { return mods; } protected JCodeModel owner() { return outer.owner(); } }