1 /* 2 * Copyright 2016 Federico Tomassetti 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.github.javaparser.symbolsolver.logic; 18 19 import com.github.javaparser.resolution.MethodUsage; 20 import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; 21 import com.github.javaparser.resolution.types.ResolvedType; 22 23 import java.lang.reflect.Method; 24 import java.lang.reflect.Parameter; 25 import java.util.Arrays; 26 import java.util.List; 27 import java.util.Optional; 28 import java.util.Set; 29 import java.util.stream.Collectors; 30 31 /** 32 * @author Federico Tomassetti 33 */ 34 public final class FunctionalInterfaceLogic { 35 FunctionalInterfaceLogic()36 private FunctionalInterfaceLogic() { 37 // prevent instantiation 38 } 39 40 /** 41 * Get the functional method defined by the type, if any. 42 */ getFunctionalMethod(ResolvedType type)43 public static Optional<MethodUsage> getFunctionalMethod(ResolvedType type) { 44 if (type.isReferenceType() && type.asReferenceType().getTypeDeclaration().isInterface()) { 45 return getFunctionalMethod(type.asReferenceType().getTypeDeclaration()); 46 } else { 47 return Optional.empty(); 48 } 49 } 50 51 /** 52 * Get the functional method defined by the type, if any. 53 */ getFunctionalMethod(ResolvedReferenceTypeDeclaration typeDeclaration)54 public static Optional<MethodUsage> getFunctionalMethod(ResolvedReferenceTypeDeclaration typeDeclaration) { 55 //We need to find all abstract methods 56 Set<MethodUsage> methods = typeDeclaration.getAllMethods().stream() 57 .filter(m -> m.getDeclaration().isAbstract()) 58 // Remove methods inherited by Object: 59 // Consider the case of Comparator which define equals. It would be considered a functional method. 60 .filter(m -> !declaredOnObject(m)) 61 .collect(Collectors.toSet()); 62 63 if (methods.size() == 1) { 64 return Optional.of(methods.iterator().next()); 65 } else { 66 return Optional.empty(); 67 } 68 } 69 isFunctionalInterfaceType(ResolvedType type)70 public static boolean isFunctionalInterfaceType(ResolvedType type) { 71 if (type.isReferenceType() && type.asReferenceType().getTypeDeclaration().hasAnnotation(FunctionalInterface.class.getCanonicalName())) { 72 return true; 73 } 74 return getFunctionalMethod(type).isPresent(); 75 } 76 getSignature(Method m)77 private static String getSignature(Method m) { 78 return String.format("%s(%s)", m.getName(), String.join(", ", Arrays.stream(m.getParameters()).map(p -> toSignature(p)).collect(Collectors.toList()))); 79 } 80 toSignature(Parameter p)81 private static String toSignature(Parameter p) { 82 return p.getType().getCanonicalName(); 83 } 84 85 private static List<String> OBJECT_METHODS_SIGNATURES = Arrays.stream(Object.class.getDeclaredMethods()) 86 .map(method -> getSignature(method)) 87 .collect(Collectors.toList()); 88 declaredOnObject(MethodUsage m)89 private static boolean declaredOnObject(MethodUsage m) { 90 return OBJECT_METHODS_SIGNATURES.contains(m.getDeclaration().getSignature()); 91 } 92 } 93