| /******************************************************************************* |
| * Copyright (c) 2005, 2008 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.refactoring.descriptors; |
| |
| import java.util.Map; |
| |
| import org.eclipse.ltk.core.refactoring.RefactoringContribution; |
| import org.eclipse.ltk.core.refactoring.RefactoringCore; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaConventions; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.refactoring.IJavaRefactorings; |
| |
| import org.eclipse.jdt.internal.core.refactoring.descriptors.JavaRefactoringDescriptorUtil; |
| |
| /** |
| * Refactoring descriptor for the introduce parameter object refactoring. |
| * <p> |
| * An instance of this refactoring descriptor may be obtained by calling |
| * {@link RefactoringContribution#createDescriptor()} on a refactoring |
| * contribution requested by invoking |
| * {@link RefactoringCore#getRefactoringContribution(String)} with the |
| * appropriate refactoring id. |
| * </p> |
| * |
| * @since 1.2 |
| * |
| * @noinstantiate This class is not intended to be instantiated by clients. |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| public class IntroduceParameterObjectDescriptor extends JavaRefactoringDescriptor { |
| |
| /** |
| * Instances of Parameter are used to describe the position of parameter and fields. |
| */ |
| public static class Parameter { |
| |
| private boolean fCreateField= false; |
| |
| private String fFieldName= null; |
| |
| private final int fIndex; |
| |
| /** |
| * Creates a new parameter object. It is not recommended to call this constructor directly. |
| * Use {@link IntroduceParameterObjectDescriptor#createParameters(IMethod)} instead. |
| * @param index the index of the parameter in the method |
| */ |
| public Parameter(int index) { |
| super(); |
| fIndex= index; |
| } |
| |
| /** |
| * The name of the field that will be created if {@link #isCreateField()} is <code>true</code> |
| * |
| * @return the field name |
| * @see #isCreateField() |
| * @see #setFieldName(String) |
| */ |
| public String getFieldName() { |
| return fFieldName; |
| } |
| |
| /** |
| * The index of the parameter in the original method signature. The parameter object has the special index {@link IntroduceParameterObjectDescriptor#PARAMETER_OBJECT_IDX}. |
| * The position in the new method signature depends on the position in the array passed to {@link IntroduceParameterObjectDescriptor#setParameters(IntroduceParameterObjectDescriptor.Parameter[])} |
| * |
| * @return returns the index of the parameter in the original method signature or {@link IntroduceParameterObjectDescriptor#PARAMETER_OBJECT_IDX} |
| * for the parameter object |
| * |
| * @see IntroduceParameterObjectDescriptor#PARAMETER_OBJECT |
| * @see IntroduceParameterObjectDescriptor#PARAMETER_OBJECT_IDX |
| * @see IntroduceParameterObjectDescriptor#setParameters(IntroduceParameterObjectDescriptor.Parameter[]) |
| */ |
| public int getIndex() { |
| return fIndex; |
| } |
| |
| /** |
| * If <code>true</code> the parameter will be removed from the method's signature and will be added |
| * to the parameter object. The default is <code>false</code> |
| * |
| * @return <code>true</code> if the parameter will be created as field, <code>false</code> if |
| * it will remain in the method |
| */ |
| public boolean isCreateField() { |
| return fCreateField; |
| } |
| |
| /** |
| * Sets whether the parameter will be removed from the method's signature or will be added to the parameter object. The |
| * default is <code>false</code>. Changing the creatField property of the parameter object will throw a {@link IllegalArgumentException} |
| * |
| * @param createField <code>true</code> if the parameter should be created as field, <code>false</code> |
| * if it will remain in the method |
| */ |
| public void setCreateField(boolean createField) { |
| if (fIndex == PARAMETER_OBJECT_IDX) |
| throw new IllegalArgumentException("You can not set create field for the parameter object"); //$NON-NLS-1$ |
| fCreateField= createField; |
| } |
| |
| |
| /** |
| * Sets the name of the field that will be created in the parameter object if {@link #isCreateField()} |
| * is <code>true</code>. Changing the fieldName of the parameter object will throw a {@link IllegalArgumentException} |
| * |
| * @param fieldName the new name of the field. A <code>null</code> indicates that the field name should be automatically derived |
| * @see #isCreateField() |
| */ |
| public void setFieldName(String fieldName) { |
| if (fIndex == PARAMETER_OBJECT_IDX) |
| throw new IllegalArgumentException("You can not set the field name of the parameter object"); //$NON-NLS-1$ |
| fFieldName= fieldName; |
| } |
| } |
| |
| private static final String PARAMETER_COUNT= "PARAMETER_COUNT"; //$NON-NLS-1$ |
| |
| private static final String PARAMETER_IDX= "PARAMETER_IDX"; //$NON-NLS-1$ |
| |
| private static final String PARAMETER_CREATE_FIELD= "PARAMETER_CREATE_FIELD"; //$NON-NLS-1$ |
| |
| private static final String PARAMETER_FIELD_NAME= "PARAMETER_FIELD_NAME"; //$NON-NLS-1$ |
| |
| private static final String CLASS_NAME= "class_name"; //$NON-NLS-1$ |
| |
| private static final String DELEGATE= "delegate"; //$NON-NLS-1$ |
| |
| private static final String DEPRECATE_DELEGATE= "deprecate_delegate"; //$NON-NLS-1$ |
| |
| private static final String GETTERS= "getters"; //$NON-NLS-1$ |
| |
| private static final String PACKAGE_NAME= "package_name"; //$NON-NLS-1$ |
| |
| private static final String PARAMETER_NAME= "parameter_name"; //$NON-NLS-1$ |
| |
| private static final String SETTERS= "setters"; //$NON-NLS-1$ |
| |
| private static final String TOP_LEVEL= "top_level"; //$NON-NLS-1$ |
| |
| /** |
| * The parameter index of the special parameter object. The value is "-1". |
| */ |
| public static final int PARAMETER_OBJECT_IDX= -1; |
| |
| /** |
| * Singleton instance that represents the parameter object |
| */ |
| public static final Parameter PARAMETER_OBJECT= new Parameter(PARAMETER_OBJECT_IDX); |
| |
| |
| /** |
| * Creates the parameters for this method. The first object is the parameter object. |
| * By default all parameters are marked for field creation |
| * |
| * @param method derive parameter from this method |
| * @return an array of parameter corresponding to the parameter declared in the method. The first object |
| * will be the parameter object. All parameter are marked for field creation |
| */ |
| public static Parameter[] createParameters(IMethod method) { |
| int length= method.getNumberOfParameters(); |
| Parameter[] result= new Parameter[length + 1]; |
| result[0]= PARAMETER_OBJECT; |
| for (int i= 0; i < length; i++) { |
| result[i + 1]= new Parameter(i); |
| result[i + 1].setCreateField(true); |
| } |
| return result; |
| } |
| |
| private String fClassName; |
| |
| private boolean fDelegate= false; |
| |
| private boolean fDeprecateDelegate= true; |
| |
| private boolean fGetters= false; |
| |
| private IMethod fMethod; |
| |
| private String fPackageName; |
| |
| private String fParameterName; |
| |
| private Parameter[] fParameters; |
| |
| private boolean fSetters= false; |
| |
| /** |
| * If <code>true</code> the class will be created as top level class. Default true |
| */ |
| private boolean fTopLevel= true; |
| |
| /** |
| * Creates a new refactoring descriptor. |
| */ |
| public IntroduceParameterObjectDescriptor() { |
| super(IJavaRefactorings.INTRODUCE_PARAMETER_OBJECT); |
| } |
| |
| /** |
| * Creates a new refactoring descriptor. |
| * |
| * @param project |
| * the non-empty name of the project associated with this |
| * refactoring, or <code>null</code> for a workspace |
| * refactoring |
| * @param description |
| * a non-empty human-readable description of the particular |
| * refactoring instance |
| * @param comment |
| * the human-readable comment of the particular refactoring |
| * instance, or <code>null</code> for no comment |
| * @param arguments |
| * a map of arguments that will be persisted and describes |
| * all settings for this refactoring |
| * @param flags |
| * the flags of the refactoring descriptor |
| * @throws IllegalArgumentException if the argument map contains invalid keys/values |
| */ |
| public IntroduceParameterObjectDescriptor(final String project, final String description, final String comment, final Map<String, String> arguments, final int flags) throws IllegalArgumentException { |
| super(IJavaRefactorings.INTRODUCE_PARAMETER_OBJECT, project, description, comment, arguments, flags); |
| initializeFromMap(arguments); |
| } |
| |
| /** |
| * The name of the class that will be generated. If <code>null</code> the refactoring will automatically choose a class name. |
| * |
| * @return the name of the class that will be generated or <code>null</code> if the name will be automatically chosen |
| */ |
| public String getClassName() { |
| return fClassName; |
| } |
| |
| /** |
| * The method the refactoring will operate on. Can be set using {@link #setMethod(IMethod)}. |
| * |
| * @return the method that the refactoring will operate on. |
| */ |
| public IMethod getMethod() { |
| return fMethod; |
| } |
| |
| /** |
| * The parameter object class will be created in this package if the top level is <code>true</code>. Can be set using |
| * {@link #setPackageName(String)}. If the package name was <code>null</code> and the method has already been set this method returns |
| * the package where the method is declared in. |
| * |
| * @return the package name that has been set or the package where the method is declared. Can return <code>null</code> |
| * if neither the package nor the method has been set |
| */ |
| public String getPackageName() { |
| if (fPackageName == null && fMethod != null) { |
| IType type= fMethod.getDeclaringType(); |
| if (type != null) |
| return type.getPackageFragment().getElementName(); |
| } |
| return fPackageName; |
| } |
| |
| /** |
| * Returns the name of the parameter. Can return <code>null</code> in which case the refactoring chooses a name. Default is <code>null</code> |
| * |
| * @return the name of the parameter. Can return <code>null</code> in which case the refactoring chooses a name. Default is <code>null</code> |
| */ |
| public String getParameterName() { |
| return fParameterName; |
| } |
| |
| /** |
| * Returns the parameters. Can return <code>null</code> if all parameters should be converted to fields. Default is <code>null</code>. |
| * |
| * @return the parameters. Can return <code>null</code> if all parameters should be converted to fields. Default is <code>null</code> |
| */ |
| public Parameter[] getParameters() { |
| return fParameters; |
| } |
| |
| /** |
| * Returns <code>true</code> if delegates will be kept. Default is <code>false</code>. |
| * |
| * @return <code>true</code> if delegates will be kept. Default is <code>false</code> |
| */ |
| public boolean isDelegate() { |
| return fDelegate; |
| } |
| |
| /** |
| * Returns <code>true</code> if delegates will be marked as deprecated. Default is <code>false</code>. |
| * |
| * @return <code>true</code> if delegates will be marked as deprecated. Default is <code>false</code> |
| */ |
| public boolean isDeprecateDelegate() { |
| return fDeprecateDelegate; |
| } |
| |
| /** |
| * Returns <code>true</code> if getters are generated for fields. Default is <code>false</code>. |
| * |
| * @return <code>true</code> if getters are generated for fields. Default is <code>false</code> |
| */ |
| public boolean isGetters() { |
| return fGetters; |
| } |
| |
| /** |
| * Returns <code>true</code> if setters are generated for fields. Default is <code>false</code>. |
| * |
| * @return <code>true</code> if setters are generated for fields. Default is <code>false</code> |
| */ |
| public boolean isSetters() { |
| return fSetters; |
| } |
| |
| /** |
| * Returns <code>true</code> if the new type is created as top level type. |
| * <code>false</code> is returned when the type is created as enclosing type |
| * of the type declaring the method declaration to be changed. Default is <code>true</code>. |
| * |
| * @return <code>true</code> if the new type is created as top level type. |
| * <code>false</code> is returned when the type is created as enclosing |
| * type of the type declaring the method declaration to be changed. Default is <code>true</code> |
| */ |
| public boolean isTopLevel() { |
| return fTopLevel; |
| } |
| |
| @Override |
| protected void populateArgumentMap() { |
| super.populateArgumentMap(); |
| JavaRefactoringDescriptorUtil.setJavaElement(fArguments, ATTRIBUTE_INPUT, getProject(), fMethod); |
| Parameter[] parameters= fParameters; |
| if (parameters == null) { |
| parameters= createParameters(fMethod); |
| } |
| JavaRefactoringDescriptorUtil.setInt(fArguments, PARAMETER_COUNT, parameters.length); |
| for (int i= 0; i < parameters.length; i++) { |
| Parameter param= parameters[i]; |
| JavaRefactoringDescriptorUtil.setInt(fArguments, JavaRefactoringDescriptorUtil.getAttributeName(PARAMETER_IDX, i), param.getIndex()); |
| JavaRefactoringDescriptorUtil.setBoolean(fArguments, JavaRefactoringDescriptorUtil.getAttributeName(PARAMETER_CREATE_FIELD, i), param.isCreateField()); |
| if (param.isCreateField()) |
| JavaRefactoringDescriptorUtil.setString(fArguments, JavaRefactoringDescriptorUtil.getAttributeName(PARAMETER_FIELD_NAME, i), param.getFieldName()); |
| } |
| JavaRefactoringDescriptorUtil.setString(fArguments, CLASS_NAME, fClassName); |
| JavaRefactoringDescriptorUtil.setString(fArguments, PACKAGE_NAME, fPackageName); |
| JavaRefactoringDescriptorUtil.setString(fArguments, PARAMETER_NAME, fParameterName); |
| JavaRefactoringDescriptorUtil.setBoolean(fArguments, DELEGATE, fDelegate); |
| JavaRefactoringDescriptorUtil.setBoolean(fArguments, DEPRECATE_DELEGATE, fDeprecateDelegate); |
| JavaRefactoringDescriptorUtil.setBoolean(fArguments, GETTERS, fGetters); |
| JavaRefactoringDescriptorUtil.setBoolean(fArguments, SETTERS, fSetters); |
| JavaRefactoringDescriptorUtil.setBoolean(fArguments, TOP_LEVEL, fTopLevel); |
| } |
| |
| private void initializeFromMap(Map<String, String> map) throws IllegalArgumentException { |
| IMethod method= (IMethod) JavaRefactoringDescriptorUtil.getJavaElement(map, ATTRIBUTE_INPUT, getProject()); |
| setMethod(method); |
| initializeParameter(map); |
| setClassName(JavaRefactoringDescriptorUtil.getString(map, CLASS_NAME, true)); |
| setPackageName(JavaRefactoringDescriptorUtil.getString(map, PACKAGE_NAME, true)); |
| setParameterName(JavaRefactoringDescriptorUtil.getString(map, PARAMETER_NAME, true)); |
| setDelegate(JavaRefactoringDescriptorUtil.getBoolean(map, DELEGATE, fDelegate)); |
| setDeprecateDelegate(JavaRefactoringDescriptorUtil.getBoolean(map, DEPRECATE_DELEGATE, fDeprecateDelegate)); |
| setGetters(JavaRefactoringDescriptorUtil.getBoolean(map, GETTERS, fGetters)); |
| setSetters(JavaRefactoringDescriptorUtil.getBoolean(map, SETTERS, fSetters)); |
| setTopLevel(JavaRefactoringDescriptorUtil.getBoolean(map, TOP_LEVEL, fTopLevel)); |
| } |
| |
| private void initializeParameter(Map<String, String> map) throws IllegalArgumentException { |
| int[] idx= JavaRefactoringDescriptorUtil.getIntArray(map, PARAMETER_COUNT, PARAMETER_IDX); |
| boolean[] createField= JavaRefactoringDescriptorUtil.getBooleanArray(map, PARAMETER_COUNT, PARAMETER_CREATE_FIELD, 0); |
| Parameter[] result=new Parameter[idx.length]; |
| for (int i= 0; i < idx.length; i++) { |
| int index= idx[i]; |
| if (index == PARAMETER_OBJECT_IDX) { |
| result[i]= new Parameter(PARAMETER_OBJECT_IDX); |
| } else { |
| Parameter parameter= new Parameter(index); |
| result[i]= parameter; |
| parameter.setCreateField(createField[i]); |
| if (createField[i]) |
| parameter.setFieldName(JavaRefactoringDescriptorUtil.getString(map, JavaRefactoringDescriptorUtil.getAttributeName(PARAMETER_FIELD_NAME, i))); |
| } |
| } |
| setParameters(result); |
| } |
| |
| /** |
| * Sets the name of the class for the generated parameter object. The name can be <code>null</code> to |
| * indicate that the refactoring should chose one. |
| * |
| * @param className the name of the generated class or <code>null</code>. Default is <code>null</code> |
| */ |
| public void setClassName(String className) { |
| fClassName= className; |
| } |
| |
| /** |
| * Sets delegate keeping. If <code>true</code> delegates will be kept. |
| * |
| * @param delegate <code>true</code> to keep delegates. Default is <code>false</code> |
| */ |
| public void setDelegate(boolean delegate) { |
| fDelegate= delegate; |
| } |
| |
| /** |
| * Sets deprecate delegate. If <code>true</code> generated delegates will be marked as deprecated. |
| * |
| * @param deprecateDelegate <code>true</code> to deprecate kept delegates. Default is <code>false</code> |
| */ |
| public void setDeprecateDelegate(boolean deprecateDelegate) { |
| fDeprecateDelegate= deprecateDelegate; |
| } |
| |
| /** |
| * Sets whether getters will be created for all fields. |
| * |
| * @param getters <code>true</code> to create getters. Default is <code>false</code>. |
| */ |
| public void setGetters(boolean getters) { |
| fGetters= getters; |
| } |
| |
| /** |
| * Sets the method. The method may not be <code>null</code>, has to exist, and has to be |
| * in a Java project. |
| * |
| * @param method the method. May not be <code>null</code> |
| */ |
| public void setMethod(IMethod method) { |
| if (method == null) |
| throw new IllegalArgumentException("The method must not be null"); //$NON-NLS-1$ |
| if (!method.exists()) |
| throw new IllegalArgumentException("The method must exist"); //$NON-NLS-1$ |
| if (method.getJavaProject() == null) |
| throw new IllegalArgumentException("The method has to be in a Java project"); //$NON-NLS-1$ |
| fMethod= method; |
| } |
| |
| /** |
| * Sets the package where the parameter object will be created in if it is created as top level class. |
| * The package can be <code>null</code> to indicate that the package of the method should be used. |
| * |
| * @param packageName the package for the top level class or <code>null</code>. Default is <code>null</code>. |
| */ |
| public void setPackageName(String packageName) { |
| fPackageName= packageName; |
| } |
| |
| /** |
| * Sets the name of the parameter object as it will appear in the method signature. |
| * The name can be <code>null</code> to indicate that the refactoring will choose a name. |
| * |
| * @param parameterName the name of the parameter or <code>null</code>. Default is <code>null</code>. |
| */ |
| public void setParameterName(String parameterName) { |
| fParameterName= parameterName; |
| } |
| |
| /** |
| * Sets the parameters. The parameters can be <code>null</code> to indicate that all parameter |
| * should be used as fields. If not <code>null</code>, the number of parameters passed has to be |
| * the number of parameter of the method + 1. One element has to be the {@link #PARAMETER_OBJECT}. |
| * Each parameter may only appear once. |
| * |
| * @param parameters the parameters or <code>null</code>. Default is <code>null</code> |
| */ |
| public void setParameters(Parameter[] parameters) { |
| fParameters= parameters; |
| } |
| |
| /** |
| * Sets whether setters will be created for all fields. |
| * |
| * @param setters <code>true</code> to create setters. Default is <code>false</code> |
| */ |
| public void setSetters(boolean setters) { |
| fSetters= setters; |
| } |
| |
| /** |
| * Sets whether the parameter object class will be created as top level class. |
| * if <code>true</code> the class will be created as top level class in the package |
| * returned by {@link #getPackageName()}. If <code>false</code> the class will be |
| * created as as nested class in the class containing the method |
| * |
| * @param topLevel <code>true</code> to create the parameter object as top level. Default is <code>true</code> |
| */ |
| public void setTopLevel(boolean topLevel) { |
| fTopLevel= topLevel; |
| } |
| |
| @Override |
| public RefactoringStatus validateDescriptor() { |
| RefactoringStatus result= super.validateDescriptor(); |
| if (!result.isOK()) |
| return result; |
| if (fMethod == null) { |
| result.addFatalError("The method must not be null"); //$NON-NLS-1$ |
| return result; |
| } |
| IJavaProject javaProject= fMethod.getJavaProject(); |
| if (javaProject == null) { |
| result.addFatalError("Can not derive Java project from method"); //$NON-NLS-1$ |
| return result; |
| } |
| String sourceLevel= javaProject.getOption(JavaCore.COMPILER_SOURCE, true); |
| String complianceLevel= javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true); |
| if (fParameters != null) { |
| if (fParameters.length - 1 != fMethod.getNumberOfParameters()) { |
| result.addFatalError("The number of parameters does not match the number of parameters of the method"); //$NON-NLS-1$ |
| } |
| boolean hasParameterObject= false; |
| for (int i= 0; i < fParameters.length; i++) { |
| Parameter parameter= fParameters[i]; |
| if (parameter.isCreateField()) { |
| String fieldName= parameter.getFieldName(); |
| if (fieldName == null) |
| result.addError("The parameter " + parameter.getIndex() + " is marked for field creation but does not have a field name"); //$NON-NLS-1$ //$NON-NLS-2$ |
| else { |
| result.merge(RefactoringStatus.create(JavaConventions.validateFieldName(fieldName, sourceLevel, complianceLevel))); |
| } |
| } |
| if (parameter == PARAMETER_OBJECT) { |
| if (hasParameterObject) |
| result.addError("Can not have more than one parameter object"); //$NON-NLS-1$ |
| else |
| hasParameterObject= true; |
| } |
| } |
| } |
| if (fClassName != null) { |
| result.merge(RefactoringStatus.create(JavaConventions.validateIdentifier(fClassName, sourceLevel, complianceLevel))); |
| } |
| if (fParameterName != null) { |
| result.merge(RefactoringStatus.create(JavaConventions.validateIdentifier(fParameterName, sourceLevel, complianceLevel))); |
| } |
| if (fPackageName != null && !"".equals(fPackageName)) { //$NON-NLS-1$ |
| result.merge(RefactoringStatus.create(JavaConventions.validatePackageName(fPackageName, sourceLevel, complianceLevel))); |
| } |
| return result; |
| } |
| } |