/*
* ******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2015, MontiCore, All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* ******************************************************************************
*/
package de.monticore.annotations;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import de.monticore.ast.ASTNode;
/**
* This is a helper class for various operations related to the {@link Visit} annotation.
*
* @author Sebastian Oberhoff
*/
public final class VisitAnnotations {
private VisitAnnotations() {
}
/**
* Extracts all the methods from the passed object carrying the {@link Visit} annotation.
*
* @param visitingObject an object with methods annotated with @visit
* @return a set containing all methods with the @visit annotation
* @throws UnsupportedOperationException if one of the methods does not meet the contract set by
* the @Visit annotation
*/
public static Set<Method> visitMethods(Object visitingObject) {
// using a set ensures that public methods, which are returned both by getMethods() and
// getDeclaredMethods(), aren't gathered twice
Set<Method> allMethods = new LinkedHashSet<>();
// gather inherited visit methods
allMethods.addAll(Arrays.asList(visitingObject.getClass().getMethods()));
// gather private visit methods
allMethods.addAll(Arrays.asList(visitingObject.getClass().getDeclaredMethods()));
Set<Method> visitMethods = new LinkedHashSet<>();
for (Method method : allMethods) {
if (method.isAnnotationPresent(Visit.class)) {
checkVisitMethod(method);
method.setAccessible(true);
visitMethods.add(method);
}
}
return visitMethods;
}
/**
* Checks the validity of a method annotated with the {@link Visit} annotation.
*
* @param visitMethod the method to be checked
* @throws UnsupportedOperationException if the method violates the contract set by the @visit
* annotation
*/
private static void checkVisitMethod(Method visitMethod) {
int parameterCount = visitMethod.getParameterCount();
if (parameterCount != 1) {
throw new UnsupportedOperationException(
"Visit methods must take exactly one argument. The method \"" + visitMethod + "\" took "
+ parameterCount + ".");
}
Class<?> parameterType = visitMethod.getParameterTypes()[0];
if (!ASTNode.class.isAssignableFrom(parameterType)) {
throw new UnsupportedOperationException(
"Visit methods may only accept subclasses of ASTNode.");
}
}
}