Advertisement
Guest User

Untitled

a guest
Oct 14th, 2019
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.64 KB | None | 0 0
  1. package com.facebook.presto.scuba.optimization;
  2.  
  3. import com.facebook.presto.spi.function.FunctionMetadata;
  4. import com.facebook.presto.spi.function.ScalarFunction;
  5. import com.facebook.presto.spi.function.ScalarOperator;
  6. import com.facebook.presto.spi.function.SqlType;
  7. import com.facebook.presto.spi.type.TypeSignature;
  8. import com.google.common.collect.ImmutableList;
  9. import com.google.common.collect.ImmutableMap;
  10. import com.google.common.collect.ImmutableSet;
  11.  
  12. import java.lang.annotation.Annotation;
  13. import java.lang.invoke.MethodHandle;
  14. import java.lang.invoke.MethodHandles;
  15. import java.lang.reflect.Method;
  16. import java.lang.reflect.Modifier;
  17. import java.lang.reflect.Parameter;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Set;
  21. import java.util.stream.Stream;
  22.  
  23. import static com.facebook.presto.scuba.optimization.ScubaScalarHeader.fromAnnotatedElement;
  24. import static com.facebook.presto.spi.function.FunctionKind.SCALAR;
  25. import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
  26. import static com.google.common.base.Preconditions.checkArgument;
  27. import static java.lang.String.format;
  28. import static java.util.Objects.requireNonNull;
  29.  
  30. public class ScubaScalarFromAnnotationsParser
  31. {
  32. private ScubaScalarFromAnnotationsParser()
  33. {
  34. }
  35.  
  36. public static Map<FunctionMetadata, MethodHandle> parseFunctionDefinitions(Class<?> clazz)
  37. {
  38. ImmutableMap.Builder<FunctionMetadata, MethodHandle> translatorBuilder = ImmutableMap.builder();
  39. for (ScalarHeaderAndMethods methods : findScalarsFromSetClass(clazz)) {
  40. translatorBuilder.putAll(scalarToFunctionMetadata(methods));
  41. }
  42.  
  43. return translatorBuilder.build();
  44. }
  45.  
  46. public static TypeSignature removeTypeParameters(TypeSignature typeSignature)
  47. {
  48. return new TypeSignature(typeSignature.getBase());
  49. }
  50.  
  51. public static FunctionMetadata removeTypeParameters(FunctionMetadata metadata)
  52. {
  53. ImmutableList.Builder<TypeSignature> argumentsBuilder = ImmutableList.builder();
  54. for (TypeSignature typeSignature : metadata.getArgumentTypes()) {
  55. argumentsBuilder.add(removeTypeParameters(typeSignature));
  56. }
  57.  
  58. if (metadata.getOperatorType().isPresent()) {
  59. return new FunctionMetadata(
  60. metadata.getOperatorType().get(),
  61. argumentsBuilder.build(),
  62. metadata.getReturnType(),
  63. metadata.getFunctionKind(),
  64. metadata.isDeterministic(),
  65. metadata.isCalledOnNullInput());
  66. }
  67. else {
  68. return new FunctionMetadata(
  69. metadata.getName(),
  70. argumentsBuilder.build(),
  71. metadata.getReturnType(),
  72. metadata.getFunctionKind(),
  73. metadata.isDeterministic(),
  74. metadata.isCalledOnNullInput());
  75. }
  76. }
  77.  
  78. private static MethodHandle getMethodHandle(Method method)
  79. {
  80. try {
  81. return MethodHandles.lookup().unreflect(method);
  82. }
  83. catch (IllegalAccessException e) {
  84. throw new RuntimeException(e);
  85. }
  86. }
  87.  
  88. private static List<ScalarHeaderAndMethods> findScalarsFromSetClass(Class<?> clazz)
  89. {
  90. ImmutableList.Builder<ScalarHeaderAndMethods> builder = ImmutableList.builder();
  91. for (Method method : findPublicMethodsWithAnnotation(clazz, SqlType.class, ScalarFunction.class, ScalarOperator.class)) {
  92. boolean annotationCondition = (method.getAnnotation(ScalarFunction.class) != null) || (method.getAnnotation(ScalarOperator.class) != null);
  93. checkArgument(annotationCondition, format("Method [%s] annotated with @SqlType is missing @ScalarFunction or @ScalarOperator", method));
  94.  
  95. for (ScubaScalarHeader header : fromAnnotatedElement(method)) {
  96. builder.add(new ScalarHeaderAndMethods(header, ImmutableSet.of(method)));
  97. }
  98. }
  99. List<ScalarHeaderAndMethods> methods = builder.build();
  100. checkArgument(!methods.isEmpty(), "Class [%s] does not have any methods annotated with @ScalarFunction or @ScalarOperator", clazz.getName());
  101.  
  102. return methods;
  103. }
  104.  
  105. private static Map<FunctionMetadata, MethodHandle> scalarToFunctionMetadata(ScalarHeaderAndMethods scalar)
  106. {
  107. ScubaScalarHeader header = scalar.getHeader();
  108.  
  109. ImmutableMap.Builder<FunctionMetadata, MethodHandle> metadataBuilder = ImmutableMap.builder();
  110. for (Method method : scalar.getMethods()) {
  111. FunctionMetadata metadata = methodToFunctionMetadata(header, method);
  112. metadataBuilder.put(removeTypeParameters(metadata), getMethodHandle(method));
  113. }
  114.  
  115. return metadataBuilder.build();
  116. }
  117.  
  118. private static FunctionMetadata methodToFunctionMetadata(ScubaScalarHeader header, Method method)
  119. {
  120. requireNonNull(header, "header is null");
  121.  
  122. // return type
  123. SqlType annotatedReturnType = method.getAnnotation(SqlType.class);
  124. checkArgument(annotatedReturnType != null, format("Method [%s] is missing @SqlType annotation", method));
  125. TypeSignature returnType = parseTypeSignature(annotatedReturnType.value(), ImmutableSet.of());
  126.  
  127. // argument type
  128. ImmutableList.Builder<TypeSignature> argumentTypes = new ImmutableList.Builder<>();
  129. for (Parameter parameter : method.getParameters()) {
  130. Annotation[] annotations = parameter.getAnnotations();
  131.  
  132. SqlType type = Stream.of(annotations)
  133. .filter(SqlType.class::isInstance)
  134. .map(SqlType.class::cast)
  135. .findFirst()
  136. .orElseThrow(() -> new IllegalArgumentException(format("Method [%s] is missing @SqlType annotation for parameter", method)));
  137. TypeSignature typeSignature = parseTypeSignature(type.value(), ImmutableSet.of());
  138. argumentTypes.add(typeSignature);
  139. }
  140.  
  141. if (header.getOperatorType().isPresent()) {
  142. return new FunctionMetadata(header.getOperatorType().get(), argumentTypes.build(), returnType, SCALAR, header.isDeterministic(), header.isCalledOnNullInput());
  143. }
  144. else {
  145. return new FunctionMetadata(header.getName(), argumentTypes.build(), returnType, SCALAR, header.isDeterministic(), header.isCalledOnNullInput());
  146. }
  147. }
  148.  
  149. @SafeVarargs
  150. private static Set<Method> findPublicMethodsWithAnnotation(Class<?> clazz, Class<? extends Annotation>... annotationClasses)
  151. {
  152. ImmutableSet.Builder<Method> methods = ImmutableSet.builder();
  153. for (Method method : clazz.getDeclaredMethods()) {
  154. for (Annotation annotation : method.getAnnotations()) {
  155. for (Class<?> annotationClass : annotationClasses) {
  156. if (annotationClass.isInstance(annotation)) {
  157. checkArgument(Modifier.isPublic(method.getModifiers()), "Method [%s] annotated with @%s must be public", method, annotationClass.getSimpleName());
  158. methods.add(method);
  159. }
  160. }
  161. }
  162. }
  163. return methods.build();
  164. }
  165.  
  166. private static class ScalarHeaderAndMethods
  167. {
  168. private final ScubaScalarHeader header;
  169. private final Set<Method> methods;
  170.  
  171. public ScalarHeaderAndMethods(ScubaScalarHeader header, Set<Method> methods)
  172. {
  173. this.header = requireNonNull(header, "header is null");
  174. this.methods = requireNonNull(methods, "methods are null");
  175. }
  176.  
  177. public ScubaScalarHeader getHeader()
  178. {
  179. return header;
  180. }
  181.  
  182. public Set<Method> getMethods()
  183. {
  184. return methods;
  185. }
  186. }
  187. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement