/**
* Copyright (C) 2005 - 2012 Eric Van Dewoestine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.eclim.plugin.jdt.command.constructor;
import java.util.HashMap;
import org.apache.commons.lang.StringUtils;
import org.eclim.Services;
import org.eclim.annotation.Command;
import org.eclim.command.CommandLine;
import org.eclim.command.Options;
import org.eclim.plugin.core.command.AbstractCommand;
import org.eclim.plugin.core.util.TemplateUtils;
import org.eclim.plugin.jdt.PluginResources;
import org.eclim.plugin.jdt.util.JavaUtils;
import org.eclim.plugin.jdt.util.TypeUtils;
import org.eclim.util.file.Position;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.formatter.CodeFormatter;
/**
* Command used to generate class constructors.
*
* @author Eric Van Dewoestine
*/
@Command(
name = "java_constructor",
options =
"REQUIRED p project ARG," +
"REQUIRED f file ARG," +
"REQUIRED o offset ARG," +
"OPTIONAL e encoding ARG," +
"OPTIONAL r properties ARG"
)
public class ConstructorCommand
extends AbstractCommand
{
private static final String TEMPLATE = "constructor.gst";
/**
* {@inheritDoc}
*/
public Object execute(CommandLine commandLine)
throws Exception
{
String project = commandLine.getValue(Options.PROJECT_OPTION);
String file = commandLine.getValue(Options.FILE_OPTION);
String propertiesOption = commandLine.getValue(Options.PROPERTIES_OPTION);
String[] properties = {};
if(propertiesOption != null){
properties = StringUtils.split(propertiesOption, ',');
}
int offset = getOffset(commandLine);
// validate supplied fields.
ICompilationUnit src = JavaUtils.getCompilationUnit(project, file);
IType type = TypeUtils.getType(src, offset);
for(int ii = 0; ii < properties.length; ii++){
if(!type.getField(properties[ii]).exists()){
throw new RuntimeException(
Services.getMessage(
"field.not.found", properties[ii], type.getElementName()));
}
}
// check if constructor already exists.
IMethod method = null;
if(properties.length == 0){
method = type.getMethod(type.getElementName(), null);
}else{
String[] fieldSigs = new String[properties.length];
for (int ii = 0; ii < properties.length; ii++){
fieldSigs[ii] = type.getField(properties[ii]).getTypeSignature();
}
method = type.getMethod(type.getElementName(), fieldSigs);
}
if(method.exists()){
throw new RuntimeException(
Services.getMessage("constructor.already.exists",
type.getElementName() + " (" + buildParams(type, properties) + ")"));
}
// find the sibling to insert before.
IJavaElement sibling = null;
IMethod[] methods = type.getMethods();
for(int ii = 0; ii < methods.length; ii++){
if(methods[ii].isConstructor()){
sibling = ii < methods.length - 1 ? methods[ii + 1] : null;
}
}
// insert before any other methods or inner classes if any.
if(sibling == null){
if(methods.length > 0){
sibling = methods[0];
}else{
IType[] types = type.getTypes();
sibling = types != null && types.length > 0 ? types[0] : null;
}
}
HashMap<String, Object> values = new HashMap<String, Object>();
values.put("type", type.getElementName());
boolean hasProperties = properties != null && properties.length > 0;
values.put("fields", hasProperties ? properties : null);
values.put("params",
hasProperties ? buildParams(type, properties) : StringUtils.EMPTY);
PluginResources resources = (PluginResources)
Services.getPluginResources(PluginResources.NAME);
String constructor = TemplateUtils.evaluate(resources, TEMPLATE, values);
Position position = TypeUtils.getPosition(
type, type.createMethod(constructor, sibling, false, null));
JavaUtils.format(
src, CodeFormatter.K_COMPILATION_UNIT,
position.getOffset(), position.getLength());
return null;
}
/**
* Builds a string of the constructor parameters.
*
* @param type The type containing the fields.
* @param fields The array of fields.
* @return The parameters string.
*/
protected String buildParams(IType type, String[] fields)
throws Exception
{
StringBuffer params = new StringBuffer();
for (int ii = 0; ii < fields.length; ii++){
if(ii != 0){
params.append(", ");
}
IField field = type.getField(fields[ii]);
params.append(Signature.getSignatureSimpleName(field.getTypeSignature()))
.append(' ').append(field.getElementName());
}
return params.toString();
}
}