blob: 14f24f813b6990a8a532ed8da3192d842b0b5f88 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.common.events.annotated;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
import org.eclipse.jetty.websocket.common.events.ParamList;
/**
* Basic scanner for Annotated Methods
*/
public abstract class AbstractMethodAnnotationScanner<T>
{
protected void assertIsPublicNonStatic(Method method)
{
int mods = method.getModifiers();
if (!Modifier.isPublic(mods))
{
StringBuilder err = new StringBuilder();
err.append("Invalid declaration of ");
err.append(method);
err.append(System.lineSeparator());
err.append("Method modifier must be public");
throw new InvalidWebSocketException(err.toString());
}
if (Modifier.isStatic(mods))
{
StringBuilder err = new StringBuilder();
err.append("Invalid declaration of ");
err.append(method);
err.append(System.lineSeparator());
err.append("Method modifier may not be static");
throw new InvalidWebSocketException(err.toString());
}
}
protected void assertIsReturn(Method method, Class<?> type)
{
if (!type.equals(method.getReturnType()))
{
StringBuilder err = new StringBuilder();
err.append("Invalid declaration of ");
err.append(method);
err.append(System.lineSeparator());
err.append("Return type must be ").append(type);
throw new InvalidWebSocketException(err.toString());
}
}
protected void assertIsVoidReturn(Method method)
{
assertIsReturn(method,Void.TYPE);
}
protected void assertUnset(CallableMethod callable, Class<? extends Annotation> annoClass, Method method)
{
if (callable != null)
{
// Attempt to add duplicate frame type (a no-no)
StringBuilder err = new StringBuilder();
err.append("Duplicate @").append(annoClass.getSimpleName()).append(" declaration on ");
err.append(method);
err.append(System.lineSeparator());
err.append("@").append(annoClass.getSimpleName()).append(" previously declared at ");
err.append(callable.getMethod());
throw new InvalidWebSocketException(err.toString());
}
}
protected void assertValidSignature(Method method, Class<? extends Annotation> annoClass, ParamList validParams)
{
assertIsPublicNonStatic(method);
assertIsReturn(method,Void.TYPE);
boolean valid = false;
// validate parameters
Class<?> actual[] = method.getParameterTypes();
for (Class<?>[] params : validParams)
{
if (isSameParameters(actual,params))
{
valid = true;
break;
}
}
if (!valid)
{
throw InvalidSignatureException.build(method,annoClass,validParams);
}
}
public boolean isAnnotation(Annotation annotation, Class<? extends Annotation> annotationClass)
{
return annotation.annotationType().equals(annotationClass);
}
public boolean isSameParameters(Class<?>[] actual, Class<?>[] params)
{
if (actual.length != params.length)
{
// skip
return false;
}
int len = params.length;
for (int i = 0; i < len; i++)
{
if (!actual[i].equals(params[i]))
{
return false; // not valid
}
}
return true;
}
protected boolean isSignatureMatch(Method method, ParamList validParams)
{
assertIsPublicNonStatic(method);
assertIsReturn(method,Void.TYPE);
// validate parameters
Class<?> actual[] = method.getParameterTypes();
for (Class<?>[] params : validParams)
{
if (isSameParameters(actual,params))
{
return true;
}
}
return false;
}
protected boolean isTypeAnnotated(Class<?> pojo, Class<? extends Annotation> expectedAnnotation)
{
return pojo.getAnnotation(expectedAnnotation) != null;
}
public abstract void onMethodAnnotation(T metadata, Class<?> pojo, Method method, Annotation annotation);
public void scanMethodAnnotations(T metadata, Class<?> pojo)
{
Class<?> clazz = pojo;
while ((clazz != null) && Object.class.isAssignableFrom(clazz))
{
for (Method method : clazz.getDeclaredMethods())
{
Annotation annotations[] = method.getAnnotations();
if ((annotations == null) || (annotations.length <= 0))
{
continue; // skip
}
for (Annotation annotation : annotations)
{
onMethodAnnotation(metadata,clazz,method,annotation);
}
}
clazz = clazz.getSuperclass();
}
}
}