/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jboss.forge.roaster.model.util;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.jboss.forge.roaster.model.Method;
import org.jboss.forge.roaster.model.MethodHolder;
import org.jboss.forge.roaster.model.source.MethodHolderSource;
import org.jboss.forge.roaster.model.source.MethodSource;
import org.jboss.forge.roaster.model.source.ParameterSource;
/**
* Utility methods for {@link MethodSource} objects
*
* @author <a href="mailto:ggastald@redhat.com">George Gastaldi</a>
*/
public class Methods
{
private Methods()
{
}
/**
* Implement the abstract methods present in a {@link MethodHolder} to the specified {@link MethodHolderSource}
*
* @param source the {@link MethodHolder} where the methods will be imported from
* @param target the {@link MethodHolderSource} where the methods will be exported to
* @return a {@link List} of the implemented methods added to the provided {@link MethodHolderSource}
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static List<MethodSource<?>> implementAbstractMethods(final MethodHolder<?> source,
final MethodHolderSource<?> target)
{
List<MethodSource<?>> methods = new ArrayList<MethodSource<?>>();
for (Method method : source.getMethods())
{
if (method.isAbstract() && !target.hasMethod(method))
{
MethodSource<?> newMethod = target.addMethod(method);
implementMethod(newMethod);
removeAllAnnotations(newMethod);
methods.add(newMethod);
}
}
return methods;
}
public static void removeAllAnnotations(final MethodSource<?> source)
{
source.removeAllAnnotations();
for (ParameterSource<?> parameterSource : source.getParameters())
{
parameterSource.removeAllAnnotations();
}
}
/**
* Implement the abstract methods present in a {@link Class} to the specified {@link MethodHolderSource}
*
* @param source the {@link Class} where the methods will be imported from
* @param target the {@link MethodHolderSource} where the methods will be exported to
* @return a {@link List} of the implemented methods added to the provided {@link MethodHolderSource}
*/
public static List<MethodSource<?>> implementAbstractMethods(final Class<?> source,
final MethodHolderSource<?> target)
{
List<MethodSource<?>> methods = new ArrayList<MethodSource<?>>();
for (java.lang.reflect.Method m : source.getMethods())
{
if (m.getDeclaringClass() == Object.class)
continue;
if (Modifier.isAbstract(m.getModifiers())
&& target.getMethod(m.getName(), m.getParameterTypes()) == null)
{
MethodSource<?> newMethod = target.addMethod(m);
implementMethod(newMethod);
removeAllAnnotations(newMethod);
methods.add(newMethod);
}
}
return methods;
}
/**
* Adds a default method implementation to the given {@link MethodSource}. This method will call
* {@link MethodSource#setAbstract(false)} before setting the body if the origin is not an interface
*
* @param source
*/
public static void implementMethod(MethodSource<?> source)
{
if (source.getOrigin().isInterface())
{
source.setBody(null);
}
else
{
if (source.isNative())
{
source.setNative(false);
}
source.setAbstract(false);
if (source.isReturnTypeVoid())
{
source.setBody("");
}
else
{
source.setBody("return " + Types.getDefaultValue(source.getReturnType().getName()) + ";");
}
}
}
/**
* @return the parameter names of a given {@link Method}
*/
public static String[] generateParameterNames(Class<?>[] parameterTypes)
{
List<String> parameterNames = new ArrayList<String>();
for (Class<?> paramType : parameterTypes)
{
// Check if we haven't already used it.
String name = toParamName(paramType.getSimpleName());
String paramName = name;
int idx = 1;
while (parameterNames.contains(paramName))
{
paramName = name + idx++;
}
parameterNames.add(paramName);
}
return parameterNames.toArray(new String[parameterNames.size()]);
}
static String toParamName(String type)
{
// Special case for java.lang types
if (Types.isBasicType(type) || Types.isJavaLang(type))
{
return String.valueOf(type.charAt(0)).toLowerCase();
}
StringBuilder name = new StringBuilder(type);
int i;
for (i = 0; i < name.length(); i++)
{
if (!Character.isUpperCase(name.charAt(i)))
{
// Go back one index
i--;
break;
}
}
if (i == 0)
name.setCharAt(0, Character.toLowerCase(name.charAt(0)));
else if (i > 0)
name.replace(0, i, name.substring(0, i).toLowerCase());
return name.toString();
}
}