001/*
002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010
011package org.eclipse.golo.runtime;
012
013import java.lang.reflect.*;
014import java.util.function.Predicate;
015import java.util.stream.Stream;
016
017import static org.eclipse.golo.runtime.TypeMatching.compareTypes;
018import static org.eclipse.golo.runtime.DecoratorsHelper.isMethodDecorated;
019import static org.eclipse.golo.runtime.TypeMatching.argumentsNumberMatches;
020
021public final class Extractors {
022  private Extractors() {
023    throw new UnsupportedOperationException("don't instantiate");
024  }
025
026  public static Stream<Constructor<?>> getConstructors(Class<?> klass) {
027    if (klass == null) {
028      return Stream.empty();
029    }
030    return Stream.of(klass.getConstructors());
031  }
032
033  public static Stream<Method> getFunctions(Class<?> klass) {
034    return getMethods(klass).filter(Extractors::isFunction);
035  }
036
037  public static Stream<Method> getMethods(Class<?> klass) {
038    if (klass == null) {
039      return Stream.empty();
040    }
041    return Stream.concat(
042        Stream.of(klass.getDeclaredMethods()),
043        Stream.of(klass.getMethods()))
044      .distinct()
045      .sorted((m1, m2) -> {
046        if (m1.isVarArgs() && !m2.isVarArgs()) {
047          return 1;
048        }
049        if (m2.isVarArgs() && !m1.isVarArgs()) {
050          return -1;
051        }
052        return compareTypes(m1.getParameterTypes(), m2.getParameterTypes());
053      });
054  }
055
056  public static Stream<Field> getFields(Class<?> klass) {
057    if (klass == null) {
058      return Stream.empty();
059    }
060    return Stream.concat(
061        Stream.of(klass.getDeclaredFields()),
062        Stream.of(klass.getFields()))
063      .distinct();
064  }
065
066  public static Stream<String> getImportedNames(Class<?> klass) {
067    if (klass == null) {
068      return Stream.empty();
069    }
070    return Stream.of(Module.imports(klass));
071  }
072
073  public static Stream<Member> getMembers(Class<?> klass) {
074    if (klass == null) {
075      return Stream.empty();
076    }
077    return Stream.concat(getMethods(klass), getFields(klass));
078  }
079
080  public static boolean isPublic(Member m) {
081    return Modifier.isPublic(m.getModifiers());
082  }
083
084  public static boolean isStatic(Member m) {
085    return Modifier.isStatic(m.getModifiers());
086  }
087
088  public static boolean isConcrete(Member m) {
089    return !Modifier.isAbstract(m.getModifiers());
090  }
091
092  public static boolean isFunction(Method m) {
093    return isConcrete(m) && isPublic(m) && isStatic(m);
094  }
095
096  public static Predicate<Member> isNamed(String name) {
097    return m -> m.getName().equals(name);
098  }
099
100  public static Predicate<Method> matchFunctionReference(String name, int arity, boolean varargs) {
101    return m ->
102      m.getName().equals(name)
103      && (isMethodDecorated(m) || argumentsNumberMatches(m.getParameterCount(), arity, varargs))
104      && (arity < 0 || m.isVarArgs() == varargs);
105  }
106
107  public static <T extends AnnotatedElement & Member> T checkDeprecation(Class<?> caller, T object) {
108    if (object.isAnnotationPresent(Deprecated.class)) {
109      Warnings.deprecatedElement(
110          (object instanceof Executable ? ((Executable) object).toGenericString()
111           : object instanceof Field ? ((Field) object).toGenericString()
112           : object.getName()),
113          caller.getName());
114    }
115    return object;
116  }
117
118}