下面列出了javax.lang.model.type.UnknownTypeException#javax.lang.model.type.IntersectionType 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private MethodDeclarationPair getFunctionalInterfaceMethodPair(TypeMirror typeMirror) {
Type type = (Type) typeMirror;
if (!internalTypes.isFunctionalInterface(type)) {
return null;
}
if (type.isIntersection()) {
return ((IntersectionType) type)
.getBounds().stream()
.filter(this::isFunctionalInterface)
.map(this::getFunctionalInterfaceMethodPair)
.findFirst()
.orElse(null);
}
return getMethods((ClassType) type).stream()
.filter(
p ->
isAbstract(p.getDeclarationMethodSymbol())
&& !isJavaLangObjectOverride(p.getDeclarationMethodSymbol()))
.findFirst()
.orElse(null);
}
@Test
public void intersection() {
IntersectionType t =
(IntersectionType)
factory.asTypeMirror(
Type.IntersectionTy.create(
ImmutableList.of(
Type.ClassTy.asNonParametricClassTy(
new ClassSymbol("java/io/Serializable")),
Type.ClassTy.asNonParametricClassTy(
new ClassSymbol("java/lang/Cloneable")))));
assertThat(t.getKind()).isEqualTo(TypeKind.INTERSECTION);
assertThat(t.getBounds())
.containsExactlyElementsIn(
factory.asTypeMirrors(
ImmutableList.of(
Type.ClassTy.asNonParametricClassTy(new ClassSymbol("java/lang/Object")),
Type.ClassTy.asNonParametricClassTy(new ClassSymbol("java/io/Serializable")),
Type.ClassTy.asNonParametricClassTy(new ClassSymbol("java/lang/Cloneable")))));
}
public List<? extends TypeMirror> getUpperBounds(TypeMirror t) {
if (t == null) {
return Collections.singletonList(
javacElements.getTypeElement("java.lang.Object").asType());
}
switch (t.getKind()) {
case INTERSECTION:
return ((IntersectionType) t).getBounds();
case TYPEVAR:
return getUpperBounds(((TypeVariable) t).getUpperBound());
case WILDCARD:
return getUpperBounds(((WildcardType) t).getExtendsBound());
default:
return Collections.singletonList(t);
}
}
@Override
public Void visitIntersection(IntersectionType t, StringBuilderAndState<TypeMirror> state) {
List<? extends TypeMirror> bounds = IgnoreCompletionFailures.in(t::getBounds);
if (state.visitingMethod) {
//the type erasure of an intersection type is the first type
if (!bounds.isEmpty()) {
bounds.get(0).accept(this, state);
}
} else {
for (TypeMirror b : bounds) {
b.accept(this, state);
state.bld.append("+");
}
}
return null;
}
@Override
protected Void doVisitIntersection(IntersectionType t, StringBuilderAndState<TypeMirror> state) {
Iterator<? extends TypeMirror> it = IgnoreCompletionFailures.in(t::getBounds).iterator();
if (it.hasNext()) {
it.next().accept(this, state);
}
TypeVisitor<Void, StringBuilderAndState<TypeMirror>> me = this;
it.forEachRemaining(b -> {
state.bld.append(" & ");
b.accept(me, state);
});
return null;
}
@Test
public void testGetUpperBoundMultipleBounds() throws IOException {
compile("class Foo<T extends java.lang.CharSequence & java.lang.Runnable> { }");
TypeMirror charSequenceType = elements.getTypeElement("java.lang.CharSequence").asType();
TypeMirror runnableType = elements.getTypeElement("java.lang.Runnable").asType();
TypeVariable tVar =
(TypeVariable) elements.getTypeElement("Foo").getTypeParameters().get(0).asType();
IntersectionType upperBound = (IntersectionType) tVar.getUpperBound();
List<? extends TypeMirror> bounds = upperBound.getBounds();
assertSame(2, bounds.size());
assertSameType(charSequenceType, bounds.get(0));
assertSameType(runnableType, bounds.get(1));
}
@Override
public StringBuilder visitIntersection(IntersectionType t, Boolean p) {
Iterator<? extends TypeMirror> it = t.getBounds().iterator();
while (it.hasNext()) {
visit(it.next(), p);
if (it.hasNext()) {
DEFAULT_VALUE.append(" & ");
}
}
return DEFAULT_VALUE;
}
private TypeMirror getFunctionalInterface(Type type) {
if (type.isIntersection()) {
return ((IntersectionType) type)
.getBounds().stream().filter(this::isFunctionalInterface).findFirst().orElse(null);
}
checkArgument(isFunctionalInterface(type));
return type;
}
public static TypeElement asTypeElement(TypeMirror t) {
if (isDeclaredType(t)) {
return (TypeElement) ((DeclaredType) t).asElement();
}
// Return the left-most component of an intersection type, for compatibility with JDK 10 and
// earlier.
if (isIntersection(t)) {
return asTypeElement(((IntersectionType) t).getBounds().iterator().next());
}
return null;
}
private void visitType(TypeMirror type) {
if (type == null) {
return;
} else if (TypeUtil.isIntersection(type)) {
for (TypeMirror bound : ((IntersectionType) type).getBounds()) {
getOrCreateNode(bound);
}
} else {
getOrCreateNode(type);
}
}
@Override
public final T visitIntersection(IntersectionType t, StringBuilderAndState<S> st) {
try {
st.depth++;
return doVisitIntersection(t, st);
} finally {
st.depth--;
}
}
@Override
public Void visitIntersection(IntersectionType t, StringBuilder p) {
for (Iterator<? extends TypeMirror> it = t.getBounds().iterator(); it.hasNext(); ) {
TypeMirror bound = it.next();
bound.accept(this, p);
if (it.hasNext()) {
p.append("&");
}
}
return null;
}
@Override
public <R, P> R accept(TypeVisitor<R, P> v, P p) {
switch (kind) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case CHAR:
case FLOAT:
case DOUBLE:
return v.visitPrimitive((PrimitiveType) this, p);
case PACKAGE:
case VOID:
case NONE:
return v.visitNoType((NoType) this, p);
case NULL:
return v.visitNull((NullType) this, p);
case ARRAY:
return v.visitArray((ArrayType) this, p);
case DECLARED:
return v.visitDeclared((DeclaredType) this, p);
case ERROR:
return v.visitError((ErrorType) this, p);
case TYPEVAR:
return v.visitTypeVariable((TypeVariable) this, p);
case WILDCARD:
return v.visitWildcard((WildcardType) this, p);
case EXECUTABLE:
return v.visitExecutable((ExecutableType) this, p);
case OTHER:
return v.visit(this, p);
case UNION:
return v.visitUnion((UnionType) this, p);
case INTERSECTION:
return v.visitIntersection((IntersectionType) this, p);
default:
throw new AssertionError(String.format("Unknown TypeKind: %s", kind));
}
}
private boolean isSameIntersectionType(IntersectionType t1, IntersectionType t2) {
List<? extends TypeMirror> t1Bounds = t1.getBounds();
List<? extends TypeMirror> t2Bounds = t2.getBounds();
if (t1Bounds.size() != t2Bounds.size()) {
return false;
}
for (TypeMirror t1Bound : t1Bounds) {
if (!listContainsType(t2Bounds, t1Bound)) {
return false;
}
}
return true;
}
@Test
public void testGetBounds() throws IOException {
compile("class Foo<T extends java.lang.Runnable & java.lang.CharSequence> { }");
TypeMirror runnableType = elements.getTypeElement("java.lang.Runnable").asType();
TypeMirror charSequenceType = elements.getTypeElement("java.lang.CharSequence").asType();
IntersectionType intersectionType = (IntersectionType) getTypeParameterUpperBound("Foo", 0);
List<? extends TypeMirror> bounds = intersectionType.getBounds();
assertSame(2, bounds.size());
assertSameType(runnableType, bounds.get(0));
assertSameType(charSequenceType, bounds.get(1));
}
@Test
public void testIsSameTypeIntersectionType() throws IOException {
compile(
Joiner.on('\n')
.join(
"class Foo<T extends java.lang.CharSequence & java.lang.Runnable> { }",
"class Bar<T extends java.lang.CharSequence & java.lang.Runnable> { }"));
IntersectionType fooType = (IntersectionType) getTypeParameterUpperBound("Foo", 0);
IntersectionType barType = (IntersectionType) getTypeParameterUpperBound("Bar", 0);
assertSameType(fooType, barType);
}
@Test
public void testIsNotSameTypeIntersectionTypeDifferentSize() throws IOException {
compile(
Joiner.on('\n')
.join(
"class Foo<T extends java.lang.CharSequence & java.lang.Runnable> { }",
"class Bar<T extends java.lang.CharSequence & java.lang.Runnable & java.io.Closeable> { }"));
IntersectionType fooType = (IntersectionType) getTypeParameterUpperBound("Foo", 0);
IntersectionType barType = (IntersectionType) getTypeParameterUpperBound("Bar", 0);
assertNotSameType(fooType, barType);
}
@Test
public void testIsNotSameTypeIntersectionTypeDifferentSizeReversed() throws IOException {
compile(
Joiner.on('\n')
.join(
"class Foo<T extends java.lang.CharSequence & java.lang.Runnable & java.io.Closeable> { }",
"class Bar<T extends java.lang.CharSequence & java.lang.Runnable> { }"));
IntersectionType fooType = (IntersectionType) getTypeParameterUpperBound("Foo", 0);
IntersectionType barType = (IntersectionType) getTypeParameterUpperBound("Bar", 0);
assertNotSameType(fooType, barType);
}
/**
* We're not exactly sure why intersection types with the same bounds but in a different order are
* considered the same type; after all, they can have different erasures. However, the javac
* implementation behaves that way, so we must as well.
*
* <p>The relevant JLS8 sections are 4.4 and 4.9, if any future person wants to go see if they can
* grok why this behavior is correct.
*/
@Test
public void testIsSameTypeIntersectionTypeDifferentOrder() throws IOException {
compile(
Joiner.on('\n')
.join(
"class Foo<T extends java.lang.CharSequence & java.lang.Runnable> { }",
"class Bar<T extends java.lang.Runnable & java.lang.CharSequence> { }"));
IntersectionType fooType = (IntersectionType) getTypeParameterUpperBound("Foo", 0);
IntersectionType barType = (IntersectionType) getTypeParameterUpperBound("Bar", 0);
assertSameType(fooType, barType);
}
@Test
public void testIsNotSameTypeIntersectionTypeDifferentContents() throws IOException {
compile(
Joiner.on('\n')
.join(
"class Foo<T extends java.lang.CharSequence & java.lang.Runnable> { }",
"class Bar<T extends java.lang.CharSequence & java.io.Closeable> { }"));
IntersectionType fooType = (IntersectionType) getTypeParameterUpperBound("Foo", 0);
IntersectionType barType = (IntersectionType) getTypeParameterUpperBound("Bar", 0);
assertNotSameType(fooType, barType);
}
@Override
public ImmutableSet<TypeVariable> visitIntersection(
IntersectionType t, Set<Element> visited) {
ImmutableSet.Builder<TypeVariable> typeVariables = ImmutableSet.builder();
for (TypeMirror intersectionType : t.getBounds()) {
typeVariables.addAll(intersectionType.accept(this, visited));
}
return typeVariables.build();
}
@Override
public Boolean visitIntersection(IntersectionType a, EqualVisitorParam p) {
if (p.type.getKind().equals(INTERSECTION)) {
IntersectionType b = (IntersectionType) p.type;
return equalLists(a.getBounds(), b.getBounds(), p.visiting);
}
return false;
}
private void verifyTypeAcceptable(TypeMirror type, Set<String> acceptable) {
if (type == null) return ;
verifyAnnotations(type.getAnnotationMirrors(), acceptable);
switch (type.getKind()) {
case BOOLEAN: case BYTE: case CHAR: case DOUBLE: case FLOAT:
case INT: case LONG: case SHORT: case VOID: case NONE: case NULL:
return ;
case DECLARED:
DeclaredType dt = (DeclaredType) type;
TypeElement outermostTypeElement = outermostTypeElement(dt.asElement());
String outermostType = outermostTypeElement.getQualifiedName().toString();
boolean isAcceptable = false;
for (String acceptablePackage : acceptable) {
if (outermostType.startsWith(acceptablePackage)) {
isAcceptable = true;
break;
}
}
if (!isAcceptable) {
error("Type not acceptable for this API: " + dt.toString());
}
for (TypeMirror bound : dt.getTypeArguments()) {
verifyTypeAcceptable(bound, acceptable);
}
break;
case ARRAY:
verifyTypeAcceptable(((ArrayType) type).getComponentType(), acceptable);
break;
case INTERSECTION:
for (TypeMirror element : ((IntersectionType) type).getBounds()) {
verifyTypeAcceptable(element, acceptable);
}
break;
case TYPEVAR:
verifyTypeAcceptable(((TypeVariable) type).getLowerBound(), acceptable);
verifyTypeAcceptable(((TypeVariable) type).getUpperBound(), acceptable);
break;
case WILDCARD:
verifyTypeAcceptable(((WildcardType) type).getExtendsBound(), acceptable);
verifyTypeAcceptable(((WildcardType) type).getSuperBound(), acceptable);
break;
default:
error("Type not acceptable for this API: " + type.toString());
break;
}
}
private void verifyTypeAcceptable(TypeMirror type, Set<String> acceptable) {
if (type == null) return ;
verifyAnnotations(type.getAnnotationMirrors(), acceptable);
switch (type.getKind()) {
case BOOLEAN: case BYTE: case CHAR: case DOUBLE: case FLOAT:
case INT: case LONG: case SHORT: case VOID: case NONE: case NULL:
return ;
case DECLARED:
DeclaredType dt = (DeclaredType) type;
TypeElement outermostTypeElement = outermostTypeElement(dt.asElement());
String outermostType = outermostTypeElement.getQualifiedName().toString();
boolean isAcceptable = false;
for (String acceptablePackage : acceptable) {
if (outermostType.startsWith(acceptablePackage)) {
isAcceptable = true;
break;
}
}
if (!isAcceptable) {
error("Type not acceptable for this API: " + dt.toString());
}
for (TypeMirror bound : dt.getTypeArguments()) {
verifyTypeAcceptable(bound, acceptable);
}
break;
case ARRAY:
verifyTypeAcceptable(((ArrayType) type).getComponentType(), acceptable);
break;
case INTERSECTION:
for (TypeMirror element : ((IntersectionType) type).getBounds()) {
verifyTypeAcceptable(element, acceptable);
}
break;
case TYPEVAR:
verifyTypeAcceptable(((TypeVariable) type).getLowerBound(), acceptable);
verifyTypeAcceptable(((TypeVariable) type).getUpperBound(), acceptable);
break;
case WILDCARD:
verifyTypeAcceptable(((WildcardType) type).getExtendsBound(), acceptable);
verifyTypeAcceptable(((WildcardType) type).getSuperBound(), acceptable);
break;
default:
error("Type not acceptable for this API: " + type.toString());
break;
}
}
private void verifyTypeAcceptable(TypeMirror type, Set<String> acceptable) {
if (type == null) return ;
verifyAnnotations(type.getAnnotationMirrors(), acceptable);
switch (type.getKind()) {
case BOOLEAN: case BYTE: case CHAR: case DOUBLE: case FLOAT:
case INT: case LONG: case SHORT: case VOID: case NONE: case NULL:
return ;
case DECLARED:
DeclaredType dt = (DeclaredType) type;
TypeElement outermostTypeElement = outermostTypeElement(dt.asElement());
String outermostType = outermostTypeElement.getQualifiedName().toString();
boolean isAcceptable = false;
for (String acceptablePackage : acceptable) {
if (outermostType.startsWith(acceptablePackage)) {
isAcceptable = true;
break;
}
}
if (!isAcceptable) {
error("Type not acceptable for this API: " + dt.toString());
}
for (TypeMirror bound : dt.getTypeArguments()) {
verifyTypeAcceptable(bound, acceptable);
}
break;
case ARRAY:
verifyTypeAcceptable(((ArrayType) type).getComponentType(), acceptable);
break;
case INTERSECTION:
for (TypeMirror element : ((IntersectionType) type).getBounds()) {
verifyTypeAcceptable(element, acceptable);
}
break;
case TYPEVAR:
verifyTypeAcceptable(((TypeVariable) type).getLowerBound(), acceptable);
verifyTypeAcceptable(((TypeVariable) type).getUpperBound(), acceptable);
break;
case WILDCARD:
verifyTypeAcceptable(((WildcardType) type).getExtendsBound(), acceptable);
verifyTypeAcceptable(((WildcardType) type).getSuperBound(), acceptable);
break;
default:
error("Type not acceptable for this API: " + type.toString());
break;
}
}
@Override
public Boolean visitIntersection(IntersectionType t, Void p) {
return false;
}
private void verifyTypeAcceptable(TypeMirror type, Set<String> acceptable) {
if (type == null) return ;
verifyAnnotations(type.getAnnotationMirrors(), acceptable);
switch (type.getKind()) {
case BOOLEAN: case BYTE: case CHAR: case DOUBLE: case FLOAT:
case INT: case LONG: case SHORT: case VOID: case NONE: case NULL:
return ;
case DECLARED:
DeclaredType dt = (DeclaredType) type;
TypeElement outermostTypeElement = outermostTypeElement(dt.asElement());
String outermostType = outermostTypeElement.getQualifiedName().toString();
boolean isAcceptable = false;
for (String acceptablePackage : acceptable) {
if (outermostType.startsWith(acceptablePackage)) {
isAcceptable = true;
break;
}
}
if (!isAcceptable) {
error("Type not acceptable for this API: " + dt.toString());
}
for (TypeMirror bound : dt.getTypeArguments()) {
verifyTypeAcceptable(bound, acceptable);
}
break;
case ARRAY:
verifyTypeAcceptable(((ArrayType) type).getComponentType(), acceptable);
break;
case INTERSECTION:
for (TypeMirror element : ((IntersectionType) type).getBounds()) {
verifyTypeAcceptable(element, acceptable);
}
break;
case TYPEVAR:
verifyTypeAcceptable(((TypeVariable) type).getLowerBound(), acceptable);
verifyTypeAcceptable(((TypeVariable) type).getUpperBound(), acceptable);
break;
case WILDCARD:
verifyTypeAcceptable(((WildcardType) type).getExtendsBound(), acceptable);
verifyTypeAcceptable(((WildcardType) type).getSuperBound(), acceptable);
break;
default:
error("Type not acceptable for this API: " + type.toString());
break;
}
}
@Override
public R visitIntersection(IntersectionType t, P p) {
scan(t.getBounds(), p);
return super.visitIntersection(t, p);
}
private void verifyTypeAcceptable(TypeMirror type, Set<String> acceptable) {
if (type == null) return ;
verifyAnnotations(type.getAnnotationMirrors(), acceptable);
switch (type.getKind()) {
case BOOLEAN: case BYTE: case CHAR: case DOUBLE: case FLOAT:
case INT: case LONG: case SHORT: case VOID: case NONE: case NULL:
return ;
case DECLARED:
DeclaredType dt = (DeclaredType) type;
TypeElement outermostTypeElement = outermostTypeElement(dt.asElement());
String outermostType = outermostTypeElement.getQualifiedName().toString();
boolean isAcceptable = false;
for (String acceptablePackage : acceptable) {
if (outermostType.startsWith(acceptablePackage)) {
isAcceptable = true;
break;
}
}
if (!isAcceptable) {
error("Type not acceptable for this API: " + dt.toString());
}
for (TypeMirror bound : dt.getTypeArguments()) {
verifyTypeAcceptable(bound, acceptable);
}
break;
case ARRAY:
verifyTypeAcceptable(((ArrayType) type).getComponentType(), acceptable);
break;
case INTERSECTION:
for (TypeMirror element : ((IntersectionType) type).getBounds()) {
verifyTypeAcceptable(element, acceptable);
}
break;
case TYPEVAR:
verifyTypeAcceptable(((TypeVariable) type).getLowerBound(), acceptable);
verifyTypeAcceptable(((TypeVariable) type).getUpperBound(), acceptable);
break;
case WILDCARD:
verifyTypeAcceptable(((WildcardType) type).getExtendsBound(), acceptable);
verifyTypeAcceptable(((WildcardType) type).getSuperBound(), acceptable);
break;
default:
error("Type not acceptable for this API: " + type.toString());
break;
}
}
private void verifyTypeAcceptable(TypeMirror type, Set<String> acceptable) {
if (type == null) return ;
verifyAnnotations(type.getAnnotationMirrors(), acceptable);
switch (type.getKind()) {
case BOOLEAN: case BYTE: case CHAR: case DOUBLE: case FLOAT:
case INT: case LONG: case SHORT: case VOID: case NONE: case NULL:
return ;
case DECLARED:
DeclaredType dt = (DeclaredType) type;
TypeElement outermostTypeElement = outermostTypeElement(dt.asElement());
String outermostType = outermostTypeElement.getQualifiedName().toString();
boolean isAcceptable = false;
for (String acceptablePackage : acceptable) {
if (outermostType.startsWith(acceptablePackage)) {
isAcceptable = true;
break;
}
}
if (!isAcceptable) {
error("Type not acceptable for this API: " + dt.toString());
}
for (TypeMirror bound : dt.getTypeArguments()) {
verifyTypeAcceptable(bound, acceptable);
}
break;
case ARRAY:
verifyTypeAcceptable(((ArrayType) type).getComponentType(), acceptable);
break;
case INTERSECTION:
for (TypeMirror element : ((IntersectionType) type).getBounds()) {
verifyTypeAcceptable(element, acceptable);
}
break;
case TYPEVAR:
verifyTypeAcceptable(((TypeVariable) type).getLowerBound(), acceptable);
verifyTypeAcceptable(((TypeVariable) type).getUpperBound(), acceptable);
break;
case WILDCARD:
verifyTypeAcceptable(((WildcardType) type).getExtendsBound(), acceptable);
verifyTypeAcceptable(((WildcardType) type).getSuperBound(), acceptable);
break;
default:
error("Type not acceptable for this API: " + type.toString());
break;
}
}