/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jooby.internal.spec; import java.lang.reflect.Type; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Function; import com.github.javaparser.ast.Node; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; public class TypeResolverImpl implements TypeResolver { private ClassLoader loader; public TypeResolverImpl(final ClassLoader loader) { this.loader = loader; } @Override public ClassLoader classLoader() { return loader; } @Override public Optional<Type> resolveType(final Node n, final String name) { Set<String> dependencies = new DependencyCollector().accept(n); return dependencies.stream() .filter(it -> it.endsWith("." + name)) .map(this::type) .findFirst() .orElseGet(() -> guessType(dependencies, name)); } private Optional<Type> guessType(final Set<String> dependencies, final String name) { Function<String, List<String>> names = p -> { ImmutableList.Builder<String> builder = ImmutableList.builder(); builder.add(p + "." + name); int $ = name.indexOf('$'); if ($ > 0) { String dclass = name.substring(0, $); if (p.endsWith("." + dclass)) { builder.add(p + "$" + name.substring($ + 1)); } } return builder.build(); }; for (String pkg : dependencies) { for (String qname : names.apply(pkg)) { Optional<Type> type = type(qname); if (type.isPresent()) { return type; } } } return type(name); } private Optional<Type> type(final String name) { return expand(name).stream() .map(n -> { try { Type type = loader.loadClass(n); return type; } catch (ClassNotFoundException ex) { return null; } }).filter(c -> c != null) .findFirst(); } private Set<String> expand(final String name) { String[] segments = name.split("\\."); StringBuilder buff = new StringBuilder(); for (String segment : segments) { buff.append(segment); char sep = Character.isUpperCase(segment.charAt(0)) ? '$' : '.'; buff.append(sep); } buff.setLength(buff.length() - 1); return ImmutableSet.of(name, buff.toString()); } }