Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.ftpix.sparknnotation.Sparknotation Maven / Gradle / Ivy
package com.ftpix.sparknnotation;
import com.ftpix.sparknnotation.annotations.*;
import com.ftpix.sparknnotation.defaultvalue.DefaultBodyTransformer;
import com.ftpix.sparknnotation.defaultvalue.DefaultTemplateEngine;
import com.ftpix.sparknnotation.defaultvalue.DefaultTransformer;
import com.ftpix.sparknnotation.interfaces.BodyTransformer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.scannotation.AnnotationDB;
import org.scannotation.ClasspathUrlFinder;
import spark.*;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class Sparknotation {
private static Map controllers = new HashMap<>();
private static Logger logger = LogManager.getLogger(Sparknotation.class);
private static BodyTransformer bodyTransformer;
private static Predicate isSparkAnnotation = a -> a.annotationType().equals(SparkGet.class)
|| a.annotationType().equals(SparkPut.class)
|| a.annotationType().equals(SparkDelete.class)
|| a.annotationType().equals(SparkOptions.class)
|| a.annotationType().equals(SparkPost.class)
|| a.annotationType().equals(SparkBefore.class)
|| a.annotationType().equals(SparkAfter.class)
|| a.annotationType().equals(SparkAfterAfter.class);
public static void init(Object... controllerInstances) throws IOException {
init(null, controllerInstances);
}
/**
* Will find all the @SparkController annotations and will process them.
*
* @param transformer a json body value
*/
public static void init(BodyTransformer transformer, Object... controllerInstances) throws IOException {
bodyTransformer = transformer;
logger.info("Json Body Transformer");
// Set> typesAnnotatedWith = new Reflections("**").getTypesAnnotatedWith(SparkController.class);
URL[] urls = ClasspathUrlFinder.findClassPaths(); // scan java.class.path
AnnotationDB db = new AnnotationDB();
db.scanArchives(urls);
Set typesAnnotatedWith =
db.getAnnotationIndex().get(SparkController.class.getName());
logger.debug("found {} classes with @SparkController annotation", typesAnnotatedWith.size());
Stream.of(controllerInstances).forEach(i -> {
try {
processController(i.getClass(), i);
} catch (IllegalAccessException | InstantiationException e) {
logger.error("Coudln't create controller instance", e);
}
});
typesAnnotatedWith.stream()
.map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
})
.forEach(clazz -> {
try {
processController(clazz, null);
} catch (InstantiationException | IllegalAccessException e) {
logger.error("Coudln't create controller instance", e);
}
});
}
/**
* Adds the controller to the list of controllers and create its endpoints
*
* @param clazz
* @param instance
*/
private static void processController(Class clazz, Object instance) throws IllegalAccessException, InstantiationException {
SparkController annotation = (SparkController) clazz.getAnnotation(SparkController.class);
String controllerName = Optional.of(annotation.name())
.filter(n -> n.trim().length() > 0)
.orElse(clazz.getCanonicalName());
if (!controllers.containsKey(controllerName)) {
final Object finalInstance;
if (instance == null) {
finalInstance = clazz.newInstance();
} else {
finalInstance = instance;
}
controllers.put(controllerName, finalInstance);
String path = Optional.ofNullable(annotation.value()).orElse("");
//find method with desired annotations
Stream.of(clazz.getDeclaredMethods())
.filter(m -> Stream.of(m.getDeclaredAnnotations()).anyMatch(isSparkAnnotation))
.forEach(m -> processMethod(path, finalInstance, m));
}
}
/**
* Process methods with any of the Spark annotation
*
* @param controllerPath the value prefix from the controller
* @param controller the controller itself
* @param method the method we're processing
*/
private static void processMethod(String controllerPath, Object controller, Method method) {
Optional.of(method).map(m -> m.getAnnotation(SparkGet.class)).ifPresent(a -> Sparknotation.createEndPoint(controllerPath, controller, method, a));
Optional.of(method).map(m -> m.getAnnotation(SparkPost.class)).ifPresent(a -> Sparknotation.createEndPoint(controllerPath, controller, method, a));
Optional.of(method).map(m -> m.getAnnotation(SparkPut.class)).ifPresent(a -> Sparknotation.createEndPoint(controllerPath, controller, method, a));
Optional.of(method).map(m -> m.getAnnotation(SparkDelete.class)).ifPresent(a -> Sparknotation.createEndPoint(controllerPath, controller, method, a));
Optional.of(method).map(m -> m.getAnnotation(SparkOptions.class)).ifPresent(a -> Sparknotation.createEndPoint(controllerPath, controller, method, a));
Optional.of(method).map(m -> m.getAnnotation(SparkBefore.class)).ifPresent(a -> Sparknotation.createBefore(controllerPath, controller, method, a));
Optional.of(method).map(m -> m.getAnnotation(SparkAfter.class)).ifPresent(a -> Sparknotation.createAfter(controllerPath, controller, method, a));
Optional.of(method).map(m -> m.getAnnotation(SparkAfterAfter.class)).ifPresent(a -> Sparknotation.createAfterAfter(controllerPath, controller, method, a));
}
/**
* Creates an endpoint depending on the controller, method and annotation
*
* @param controllerPath The path prefix from the controller
* @param controller the controller itself
* @param method the method that the endpoint is going to call
* @param annotation the Sparknotation annotation
*/
private static void createEndPoint(String controllerPath, Object controller, Method method, Annotation annotation) {
String value = null;
ResponseTransformer transformer = null;
TemplateEngine templateEngine = null;
String acceptType = "*/*";
String sparkMethod = null;
try {
switch (annotation.annotationType().getSimpleName()) {
case "SparkGet":
SparkGet get = (SparkGet) annotation;
value = get.value();
transformer = get.transformer().newInstance();
templateEngine = get.templateEngine().newInstance();
acceptType = get.accept();
sparkMethod = "get";
break;
case "SparkPost":
SparkPost post = (SparkPost) annotation;
value = post.value();
transformer = post.transformer().newInstance();
templateEngine = post.templateEngine().newInstance();
acceptType = post.accept();
sparkMethod = "post";
break;
case "SparkPut":
SparkPut put = (SparkPut) annotation;
value = put.value();
transformer = put.transformer().newInstance();
templateEngine = put.templateEngine().newInstance();
acceptType = put.accept();
sparkMethod = "put";
break;
case "SparkDelete":
SparkDelete delete = (SparkDelete) annotation;
value = delete.value();
transformer = delete.transformer().newInstance();
templateEngine = delete.templateEngine().newInstance();
acceptType = delete.accept();
sparkMethod = "delete";
break;
case "SparkOptions":
SparkOptions opts = (SparkOptions) annotation;
value = opts.value();
transformer = opts.transformer().newInstance();
templateEngine = opts.templateEngine().newInstance();
acceptType = opts.accept();
sparkMethod = "options";
break;
}
} catch (InstantiationException | IllegalAccessException e) {
logger.error("Couldn't create value, using DefaultTransformer", e);
transformer = new DefaultTransformer();
templateEngine = new DefaultTemplateEngine();
sparkMethod = null;
}
final String path = (controllerPath + value).trim();
Class spark = Spark.class;
List sparkMethodParams = new ArrayList<>();
sparkMethodParams.add(String.class);
sparkMethodParams.add(String.class);
try {
//method that use a template
if (method.getReturnType().equals(ModelAndView.class)) {
sparkMethodParams.add(Route.class);
Optional optionalMethod = Optional.ofNullable(spark.getMethod(sparkMethod, sparkMethodParams.toArray(new Class[sparkMethodParams.size()])));
final TemplateEngine finalTemplateEngine = templateEngine;
Route route = (req, res) -> {
return finalTemplateEngine.render(
(ModelAndView) methodContent(controller, method, req, res)
);
};
if (optionalMethod.isPresent()) {
Method m = optionalMethod.get();
logger.info("Creating {} [{}] on controller: {} with TemplateEngine {}", sparkMethod, path, controller.getClass(), templateEngine.getClass());
m.invoke(null, path, acceptType, route);
}
} else { //normal methods
sparkMethodParams.add(Route.class);
sparkMethodParams.add(ResponseTransformer.class);
Optional optionalMethod = Optional.ofNullable(spark.getMethod(sparkMethod, sparkMethodParams.toArray(new Class[sparkMethodParams.size()])));
Route route = (req, res) -> methodContent(controller, method, req, res);
if (optionalMethod.isPresent()) {
Method m = optionalMethod.get();
logger.info("Creating {} [{}] on controller: {} with ResponseTransformer {}", sparkMethod, path, controller.getClass(), transformer.getClass());
m.invoke(null, path, acceptType, route, transformer);
}
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
logger.error("Couldn't create Spark endpoint");
throw new RuntimeException(e);
}
// Spark.options(path, acceptType,(request, response) -> methodContent(controller,method, request, response), value);
}
/**
* Creates a Spark before endpoint
*
* @param controllerPath the value prefix from the controller
* @param controller the controller itself
* @param method the method we're processing
* @param before the annotation
*/
private static void createBefore(String controllerPath, Object controller, Method method, SparkBefore before) {
String path = (controllerPath + before.value()).trim();
if (path.length() > 0) {
logger.info("Creating before [{}] on controller: {}", path, controller.getClass());
Spark.before(path, (request, response) -> beforeAfterContent(controller, method, request, response));
} else {
logger.info("Creating before [no-value] on controller: {}", controller.getClass());
Spark.before((request, response) -> beforeAfterContent(controller, method, request, response));
}
}
/**
* Creates a Spark After endpoint
*
* @param controllerPath the value prefix from the controller
* @param controller the controller itself
* @param method the method we're processing
* @param after the annotation
*/
private static void createAfter(String controllerPath, Object controller, Method method, SparkAfter after) {
String path = (controllerPath + after.value()).trim();
if (path.length() > 0) {
logger.info("Creating After [{}] on controller: {}", path, controller.getClass());
Spark.after(path, (request, response) -> beforeAfterContent(controller, method, request, response));
} else {
logger.info("Creating After [no-value] on controller: {}", controller.getClass());
Spark.after((request, response) -> beforeAfterContent(controller, method, request, response));
}
}
/**
* Creates a Spark AfterAfter endpoint
*
* @param controllerPath the value prefix from the controller
* @param controller the controller itself
* @param method the method we're processing
* @param afterAfter the annotation
*/
private static void createAfterAfter(String controllerPath, Object controller, Method method, SparkAfterAfter afterAfter) {
String path = (controllerPath + afterAfter.value()).trim();
if (path.length() > 0) {
logger.info("Creating afterAfter [{}] on controller: {}", path, controller.getClass());
Spark.afterAfter(path, (request, response) -> beforeAfterContent(controller, method, request, response));
} else {
logger.info("Creating afterAfter [no-value] on controller: {}", controller.getClass());
Spark.afterAfter((request, response) -> beforeAfterContent(controller, method, request, response));
}
}
/**
* Calling the method from the controller for before and after
*
* @param controller
* @param method
* @param request the Spark request object
* @param response the Spark response object
* @return the result of the controller's method
* @throws InvocationTargetException if the invocation of the method fails
* @throws IllegalAccessException if the invocation of the method fails
*/
private static void beforeAfterContent(Object controller, Method method, Request request, Response response) throws InvocationTargetException, IllegalAccessException {
List params = buildParamList(method, request, response);
logger.info("Params {}", params);
method.invoke(controller, params.toArray());
}
/**
* Calling the method from the controller
*
* @param controller
* @param method
* @param request the Spark request object
* @param response the Spark response object
* @return the result of the controller's method
* @throws InvocationTargetException if the invocation of the method fails
* @throws IllegalAccessException if the invocation of the method fails
*/
private static Object methodContent(Object controller, Method method, Request request, Response response) throws InvocationTargetException, IllegalAccessException {
List params = buildParamList(method, request, response);
logger.info("Params {}", params);
return method.invoke(controller, params.toArray());
}
/**
* Builds the parameter list to be used with java reflection invoke method
*
* @param method the controller method
* @param request the Spark request object
* @param response the Spark response object
* @return
*/
private static List buildParamList(Method method, Request request, Response response) {
List params = new ArrayList<>();
Stream.of(method.getParameters())
.forEach(p -> {
if (p.getType().equals(Request.class)) {
params.add(request);
} else if (p.getType().equals(Response.class)) {
params.add(response);
} else if (p.getDeclaredAnnotations().length == 1) {
logger.info(p.getType());
Optional.ofNullable(p.getDeclaredAnnotation(SparkParam.class))
.ifPresent(a -> {
Object param = getParamValue(request.params(a.value()), p.getType());
logger.info("Param of type {} has SparkParam annotation with value [{}]", p.getType(), a.value());
params.add(param);
});
Optional.ofNullable(p.getDeclaredAnnotation(SparkQueryParam.class))
.ifPresent(a -> {
Object param = getParamValue(request.queryParams(a.value()), p.getType());
logger.info("Param of type {} has SparkQueryParam annotation with value [{}]", p.getType(), a.value());
params.add(param);
});
Optional.ofNullable(p.getDeclaredAnnotation(SparkHeader.class))
.ifPresent(a -> {
Object param = getParamValue(request.headers(a.value()), p.getType());
logger.info("Param of type {} has SparkHeader annotation with value [{}]", p.getType(), a.value());
params.add(param);
});
Optional.ofNullable(p.getDeclaredAnnotation(SparkSplat.class))
.filter(a -> p.getType().equals(String.class))
.ifPresent(a -> {
Object param = request.splat()[a.value()];
logger.info("Param of type {} has SparkSplat annotation with value [{}]", p.getType(), a.value());
params.add(param);
});
Optional.ofNullable(p.getDeclaredAnnotation(SparkBody.class))
.ifPresent(a -> {
Object param;
BodyTransformer transformer;
if (a.value().equals(DefaultBodyTransformer.class)) {
transformer = bodyTransformer;
} else {
try {
transformer = a.value().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
transformer = new DefaultBodyTransformer();
logger.error("Couldn't create the body value");
}
}
param = transformer.transform(request.body(), p.getType());
logger.info("Param of type {} has SparkJsonBody annotation", p.getType());
params.add(param);
});
}
});
return params;
}
/**
* Gets the parameter value and convert it to the same type as the controller method's parameter
*
* @param requestParam the value of the parameter
* @param clazz the class we're expecting
* @return
*/
private static Object getParamValue(String requestParam, Class clazz) {
if (clazz.equals(int.class) || clazz.equals(Integer.class)) {
if (requestParam != null) {
return Integer.parseInt(requestParam);
} else {
return clazz.equals(int.class) ? 0 : null;
}
} else if (clazz.equals(float.class) || clazz.equals(Float.class)) {
if (requestParam != null) {
return Float.parseFloat(requestParam);
} else {
return clazz.equals(float.class) ? 0 : null;
}
} else if (clazz.equals(double.class) || clazz.equals(Double.class)) {
if (requestParam != null) {
return Double.parseDouble(requestParam);
} else {
return clazz.equals(double.class) ? 0 : null;
}
} else if (clazz.equals(boolean.class) || clazz.equals(Boolean.class)) {
if (requestParam != null) {
return Boolean.parseBoolean(requestParam);
} else {
return clazz.equals(boolean.class) ? false : null;
}
} else if (clazz.equals(long.class) || clazz.equals(Long.class)) {
if (requestParam != null) {
return Long.parseLong(requestParam);
} else {
return clazz.equals(long.class) ? 0 : null;
}
} else {
return requestParam;
}
}
/**
* Gets back a controller by its value
*
* @param name the value of the controller
* @param clazz the class of it
* @param
* @return
*/
public static T getController(String name, Class clazz) {
return (T) controllers.get(name);
}
/**
* Gets a controller by its class as we won't have more than a single controller by class
*
* @param clazz the class of the controller
* @param
* @return
*/
public static T getController(Class clazz) {
return (T) controllers.values().stream().filter(c -> c.getClass().equals(clazz)).findFirst().orElse(null);
}
}