AptAssignabilityUtils.java
- /*
- * Copyright © 2017, Salesforce.com, Inc
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the <organization> nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package com.salesforce.apt.graph.types.impl;
- import javax.lang.model.element.ExecutableElement;
- import javax.lang.model.element.TypeElement;
- import javax.lang.model.type.TypeMirror;
- import javax.lang.model.util.Elements;
- import javax.lang.model.util.Types;
- import com.salesforce.apt.graph.model.InstanceModel;
- import com.salesforce.apt.graph.naming.NamingTools;
- import com.salesforce.apt.graph.types.AssignabilityUtils;
- /**
- * Compares types stored in the DefinitionGraph with the best available utils, Types and Elements in the case of apt.
- */
- public class AptAssignabilityUtils implements AssignabilityUtils {
- private Types typeUtils;
- private Elements elementUtils;
-
- public AptAssignabilityUtils(Types types, Elements elements) {
- typeUtils = types;
- elementUtils = elements;
- }
-
- /**
- * Given two instances models, the subject and target, it is determined
- * if the subject can be assigned to the dependency on the subject, from the
- * target.
- *
- * @param subject instance to be injected in to the target
- * @param target instance to have the subject injected in to it.
- * @return whether the target can be safely injected in to the correct parameter of the target.
- */
- public boolean isAssignableFrom(InstanceModel subject, InstanceModel target) {
- ExecutableElement factoryOrConstructor = lookUpElement(subject);
- TypeMirror subjectElementType = null;
- if ("<init>".equals(factoryOrConstructor.getSimpleName().toString())) {
- subjectElementType = factoryOrConstructor.getEnclosingElement().asType();
- } else {
- subjectElementType = factoryOrConstructor.getReturnType();
- }
- int count = 0;
- while (!target.getDependencies().get(count).getIdentity().equals(subject.getIdentity())) {
- count ++;
- }
- TypeMirror targetElementType = lookUpElement(target).getParameters().get(count).asType();
- return typeUtils.isAssignable(subjectElementType, targetElementType);
- }
-
- /**
- * Find's the executable element that will have the necessary type
- * information extracted from it.
- *
- * @param target the instance model that is our target
- * @return the element in question
- */
- public ExecutableElement lookUpElement(final InstanceModel target) {
- //Prior I had used the cached instances of the source element, since idea reuses compiler instances,
- //and hence AptProcessor instances that proves dangerous as the Type references for the same class/type
- //are not portable across different compilation rounds.
- //
- // Leaving this as a warning to my future self.
- //
- //if (target.getSourceElement().isPresent()) {
- // return (ExecutableElement) target.getSourceElement().get();
- //} else {
- TypeElement type = elementUtils.getTypeElement(target.getOwningDefinition().replace('$', '.'));
- final NamingTools names = new NamingTools();
- return type.getEnclosedElements().stream().filter(e ->
- names.elementToName(e).equals(target.getElementLocation()) && ExecutableElement.class.isAssignableFrom(e.getClass()))
- .findFirst()
- .map(e -> (ExecutableElement) e)
- .get();
- }
-
- /* If the above doesn't work, this handles all but ?, &, | in types.
- *
- public boolean isAssignableFrom(String subject, String target) {
- ParseType subjectType = ParseType.parse(subject);
- ParseType targetType = ParseType.parse(target);
- return typeUtils.isAssignable(from(subjectType),
- from(targetType));
- }
-
- public TypeMirror from(ParseType parsed) {
- return typeUtils.getDeclaredType(elementUtils.getTypeElement(parsed.getType()),
- parsed.getParameters().stream().map(p -> from(p)).toArray(i -> new TypeMirror[i]));
- }
- */
- }