DefaultElementQuery.java
/*
* Copyright 2017-2021 original authors
*
* Licensed 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
*
* https://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 io.micronaut.inject.ast;
import io.micronaut.context.annotation.Bean;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.AnnotationUtil;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
@Internal
final class DefaultElementQuery<T extends Element> implements ElementQuery<T>, ElementQuery.Result<T> {
private static final ClassElement ONLY_ACCESSIBLE_MARKER = ClassElement.of(DefaultElementQuery.class);
private final Class<T> elementType;
private final ClassElement onlyAccessibleType;
private final boolean onlyDeclared;
private final boolean onlyAbstract;
private final boolean onlyConcrete;
private final boolean onlyInjected;
private final List<Predicate<String>> namePredicates;
private final List<Predicate<AnnotationMetadata>> annotationPredicates;
private final List<Predicate<Set<ElementModifier>>> modifiersPredicates;
private final List<Predicate<T>> elementPredicates;
private final List<Predicate<ClassElement>> typePredicates;
private final boolean onlyInstance;
private final boolean onlyStatic;
private final boolean includeEnumConstants;
private final boolean includeOverriddenMethods;
private final boolean includeHiddenElements;
private final boolean excludePropertyElements;
private final int hashcode;
DefaultElementQuery(Class<T> elementType) {
this(elementType, null, false, false, false, false, false, false, false, false, false, false, null, null, null, null, null);
}
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultElementQuery(
Class<T> elementType,
ClassElement onlyAccessibleType,
boolean onlyDeclared,
boolean onlyAbstract,
boolean onlyConcrete,
boolean onlyInjected,
boolean onlyInstance,
boolean onlyStatic,
boolean includeEnumConstants,
boolean includeOverriddenMethods,
boolean includeHiddenElements,
boolean excludePropertyElements,
List<Predicate<AnnotationMetadata>> annotationPredicates,
List<Predicate<Set<ElementModifier>>> modifiersPredicates,
List<Predicate<T>> elementPredicates,
List<Predicate<String>> namePredicates, List<Predicate<ClassElement>> typePredicates) {
this.elementType = elementType;
this.onlyAccessibleType = onlyAccessibleType;
this.onlyDeclared = onlyDeclared;
this.onlyAbstract = onlyAbstract;
this.onlyConcrete = onlyConcrete;
this.onlyInjected = onlyInjected;
this.namePredicates = namePredicates;
this.annotationPredicates = annotationPredicates;
this.modifiersPredicates = modifiersPredicates;
this.elementPredicates = elementPredicates;
this.onlyInstance = onlyInstance;
this.onlyStatic = onlyStatic;
this.includeEnumConstants = includeEnumConstants;
this.includeOverriddenMethods = includeOverriddenMethods;
this.includeHiddenElements = includeHiddenElements;
this.excludePropertyElements = excludePropertyElements;
this.typePredicates = typePredicates;
this.hashcode = Objects.hash(elementType, onlyAccessibleType, onlyDeclared, onlyAbstract, onlyConcrete, onlyInjected, namePredicates, annotationPredicates, modifiersPredicates, elementPredicates, typePredicates, onlyInstance, onlyStatic, includeEnumConstants, includeOverriddenMethods, includeHiddenElements, excludePropertyElements);
}
@Override
public boolean isOnlyAbstract() {
return onlyAbstract;
}
@Override
public boolean isOnlyInjected() {
return onlyInjected;
}
@Override
public boolean isOnlyConcrete() {
return onlyConcrete;
}
@Override
public Class<T> getElementType() {
return elementType;
}
@Override
public boolean isOnlyAccessible() {
return onlyAccessibleType != null;
}
@Override
public Optional<ClassElement> getOnlyAccessibleFromType() {
if (onlyAccessibleType != ONLY_ACCESSIBLE_MARKER) {
return Optional.ofNullable(onlyAccessibleType);
}
return Optional.empty();
}
@Override
public boolean isOnlyDeclared() {
return onlyDeclared;
}
@Override
public boolean isOnlyInstance() {
return onlyInstance;
}
@Override
public boolean isOnlyStatic() {
return onlyStatic;
}
@Override
public boolean isIncludeEnumConstants() {
return includeEnumConstants;
}
@Override
public boolean isIncludeOverriddenMethods() {
return includeOverriddenMethods;
}
@Override
public boolean isIncludeHiddenElements() {
return includeHiddenElements;
}
@Override
public boolean isExcludePropertyElements() {
return excludePropertyElements;
}
@Override
public List<Predicate<String>> getNamePredicates() {
if (namePredicates == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(namePredicates);
}
@NonNull
@Override
public List<Predicate<ClassElement>> getTypePredicates() {
if (typePredicates == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(typePredicates);
}
@Override
public List<Predicate<AnnotationMetadata>> getAnnotationPredicates() {
if (annotationPredicates == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(annotationPredicates);
}
@Override
public List<Predicate<Set<ElementModifier>>> getModifierPredicates() {
if (modifiersPredicates == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(modifiersPredicates);
}
@Override
public List<Predicate<T>> getElementPredicates() {
if (elementPredicates == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(elementPredicates);
}
@NonNull
@Override
public ElementQuery<T> onlyDeclared() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
true,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public ElementQuery<T> onlyInjected() {
final List<Predicate<AnnotationMetadata>> annotationPredicates = this.annotationPredicates != null ? new ArrayList<>(this.annotationPredicates) : new ArrayList<>(1);
annotationPredicates.add((metadata) ->
metadata.hasDeclaredAnnotation(AnnotationUtil.INJECT) ||
(metadata.hasDeclaredStereotype(AnnotationUtil.QUALIFIER) && !metadata.hasDeclaredAnnotation(Bean.class)) ||
metadata.hasDeclaredAnnotation(AnnotationUtil.PRE_DESTROY) ||
metadata.hasDeclaredAnnotation(AnnotationUtil.POST_CONSTRUCT));
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract,
onlyConcrete,
true,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> onlyConcrete() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, true,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> onlyAbstract() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
true, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> onlyAccessible() {
return new DefaultElementQuery<>(
elementType,
ONLY_ACCESSIBLE_MARKER,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> onlyAccessible(ClassElement fromType) {
return new DefaultElementQuery<>(
elementType,
fromType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public ElementQuery<T> onlyInstance() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
true,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public ElementQuery<T> onlyStatic() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
true,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public ElementQuery<T> includeEnumConstants() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
true,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public ElementQuery<T> includeOverriddenMethods() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
true,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public ElementQuery<T> includeHiddenElements() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
true,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public ElementQuery<T> excludePropertyElements() {
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
true,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> named(@NonNull Predicate<String> predicate) {
Objects.requireNonNull(predicate, "Predicate cannot be null");
List<Predicate<String>> namePredicates;
if (this.namePredicates != null) {
namePredicates = new ArrayList<>(this.namePredicates);
namePredicates.add(predicate);
} else {
namePredicates = Collections.singletonList(predicate);
}
return new DefaultElementQuery<>(
elementType,
onlyAccessibleType,
onlyDeclared,
onlyAbstract,
onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates,
modifiersPredicates,
elementPredicates,
namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> typed(@NonNull Predicate<ClassElement> predicate) {
Objects.requireNonNull(predicate, "Predicate cannot be null");
List<Predicate<ClassElement>> typePredicates;
if (this.typePredicates != null) {
typePredicates = new ArrayList<>(this.typePredicates);
typePredicates.add(predicate);
} else {
typePredicates = Collections.singletonList(predicate);
}
return new DefaultElementQuery<>(
elementType,
onlyAccessibleType,
onlyDeclared,
onlyAbstract,
onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates,
modifiersPredicates,
elementPredicates,
namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> annotated(@NonNull Predicate<AnnotationMetadata> predicate) {
Objects.requireNonNull(predicate, "Predicate cannot be null");
List<Predicate<AnnotationMetadata>> annotationPredicates;
if (this.annotationPredicates != null) {
annotationPredicates = new ArrayList<>(this.annotationPredicates);
annotationPredicates.add(predicate);
} else {
annotationPredicates = Collections.singletonList(predicate);
}
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared,
onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> modifiers(@NonNull Predicate<Set<ElementModifier>> predicate) {
Objects.requireNonNull(predicate, "Predicate cannot be null");
List<Predicate<Set<ElementModifier>>> modifierPredicates;
if (this.modifiersPredicates != null) {
modifierPredicates = new ArrayList<>(this.modifiersPredicates);
modifierPredicates.add(predicate);
} else {
modifierPredicates = Collections.singletonList(predicate);
}
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared, onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifierPredicates, elementPredicates, namePredicates,
typePredicates);
}
@NonNull
@Override
public ElementQuery<T> filter(@NonNull Predicate<T> predicate) {
Objects.requireNonNull(predicate, "Predicate cannot be null");
List<Predicate<T>> elementPredicates;
if (this.elementPredicates != null) {
elementPredicates = new ArrayList<>(this.elementPredicates);
elementPredicates.add(predicate);
} else {
elementPredicates = Collections.singletonList(predicate);
}
return new DefaultElementQuery<>(
elementType, onlyAccessibleType,
onlyDeclared, onlyAbstract, onlyConcrete,
onlyInjected,
onlyInstance,
onlyStatic,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
excludePropertyElements,
annotationPredicates, modifiersPredicates, elementPredicates, namePredicates,
typePredicates);
}
@Override
public Result<T> withoutPredicates() {
return new DefaultElementQuery<>(
elementType,
null,
false,
false,
false,
false,
false,
false,
includeEnumConstants,
includeOverriddenMethods,
includeHiddenElements,
false,
null,
null,
null,
namePredicates, // Keep this to allow selecting only specific element
null);
}
@NonNull
@Override
public Result<T> result() {
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultElementQuery<?> that = (DefaultElementQuery<?>) o;
return onlyDeclared == that.onlyDeclared && onlyAbstract == that.onlyAbstract && onlyConcrete == that.onlyConcrete && onlyInjected == that.onlyInjected && onlyInstance == that.onlyInstance && onlyStatic == that.onlyStatic && includeEnumConstants == that.includeEnumConstants && includeOverriddenMethods == that.includeOverriddenMethods && includeHiddenElements == that.includeHiddenElements && excludePropertyElements == that.excludePropertyElements && Objects.equals(elementType, that.elementType) && Objects.equals(onlyAccessibleType, that.onlyAccessibleType) && Objects.equals(namePredicates, that.namePredicates) && Objects.equals(annotationPredicates, that.annotationPredicates) && Objects.equals(modifiersPredicates, that.modifiersPredicates) && Objects.equals(elementPredicates, that.elementPredicates) && Objects.equals(typePredicates, that.typePredicates);
}
@Override
public int hashCode() {
return hashcode;
}
}