/*
Copyright 2014-2017 Immutables Authors and Contributors
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
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.immutables.value.processor.meta;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import com.google.common.collect.ObjectArrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nullable;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.immutables.generator.ClasspathFence;
import org.immutables.generator.SourceExtraction;
import org.immutables.value.Value;
import org.immutables.value.processor.encode.EncMetadataMirror;
import org.immutables.value.processor.encode.EncodingInfo;
import org.immutables.value.processor.encode.EncodingMirror;
import org.immutables.value.processor.encode.Inflater;
import org.immutables.value.processor.encode.Instantiator;
import org.immutables.value.processor.encode.Type;
import org.immutables.value.processor.meta.Styles.UsingName.TypeNames;
import static com.google.common.base.Verify.verify;
@Value.Enclosing
public class Proto {
private Proto() {}
static final Type.Factory TYPE_FACTORY = new Type.Producer();
private static final Inflater ENCODING_INFLATER = new Inflater(TYPE_FACTORY);
final static class Interning {
private final Interner<DeclaringPackage> packageInterner = Interners.newStrongInterner();
private final Interner<DeclaringType> typeInterner = Interners.newStrongInterner();
private final Interner<Protoclass> protoclassInterner = Interners.newStrongInterner();
DeclaringPackage forPackage(DeclaringPackage declaringPackage) {
return packageInterner.intern(declaringPackage);
}
DeclaringType forType(DeclaringType declaringType) {
return typeInterner.intern(declaringType);
}
Protoclass forProto(Protoclass protoclass) {
return protoclassInterner.intern(protoclass);
}
}
@Value.Immutable(builder = false)
public static abstract class MetaAnnotated {
private static final ConcurrentMap<String, MetaAnnotated> cache = new ConcurrentHashMap<>(16, 0.7f, 1);
@Value.Parameter
@Value.Auxiliary
public abstract Element element();
@Value.Parameter
@Value.Auxiliary
public abstract String qualifiedName();
@Value.Parameter
@Value.Auxiliary
public abstract Environment environment();
@Value.Derived
@Value.Auxiliary
public Set<EncodingInfo> encodings() {
if (qualifiedName().endsWith("Enabled")
|| CustomImmutableAnnotations.annotations().contains(qualifiedName())
|| style().isPresent()) {
// See if it is encoding enabled itself
Optional<EncodingInfo> encoding = EncMetadataMirror.find(element()).transform(ENCODING_INFLATER);
if (encoding.isPresent()) {
return encoding.asSet();
}
// trying to find it as meta-meta annotation
List<EncodingInfo> result = new ArrayList<>();
for (AnnotationMirror m : element().getAnnotationMirrors()) {
MetaAnnotated metaAnnotated = MetaAnnotated.from(m, environment());
result.addAll(metaAnnotated.encodings());
}
if (!result.isEmpty()) {
return FluentIterable.from(result).toSet();
}
}
return ImmutableSet.of();
}
@Value.Derived
@Value.Auxiliary
public Optional<StyleInfo> style() {
return StyleMirror.find(element()).transform(ToStyleInfo.FUNCTION);
}
@Value.Derived
@Value.Auxiliary
public Optional<String[]> depluralize() {
Optional<DepluralizeMirror> d = DepluralizeMirror.find(element());
if (d.isPresent()) {
return Optional.of(d.get().dictionary());
}
return Optional.absent();
}
@Value.Derived
@Value.Auxiliary
public Optional<Long> serialVersion() {
if (!environment().hasSerialModule()) {
return Optional.absent();
}
Optional<VersionMirror> version = VersionMirror.find(element());
return version.isPresent()
? Optional.of(version.get().value())
: Optional.<Long>absent();
}
@Value.Derived
@Value.Auxiliary
public boolean isSerialStructural() {
return environment().hasSerialModule()
&& StructuralMirror.isPresent(element());
}
@Value.Derived
@Value.Auxiliary
public boolean isJacksonSerialized() {
return environment().hasJacksonLib()
&& isJacksonSerializedAnnotated(element());
}
@Value.Derived
@Value.Auxiliary
public boolean isJacksonDeserialized() {
return environment().hasJacksonLib()
&& isJacksonDeserializedAnnotated(element());
}
@Value.Derived
@Value.Auxiliary
public boolean isJacksonJsonTypeInfo() {
return environment().hasJacksonLib()
&& isJacksonJsonTypeInfoAnnotated(element());
}
@Value.Derived
@Value.Auxiliary
public boolean isJsonQualifier() {
return environment().hasOkJsonLib()
&& OkQualifierMirror.isPresent(element());
}
@Value.Derived
@Value.Auxiliary
public boolean isEnclosing() {
return EnclosingMirror.isPresent(element());
}
public static MetaAnnotated from(AnnotationMirror mirror, Environment environment) {
TypeElement element = (TypeElement) mirror.getAnnotationType().asElement();
String name = element.getQualifiedName().toString();
@Nullable MetaAnnotated metaAnnotated = cache.get(name);
if (metaAnnotated == null) {
metaAnnotated = ImmutableProto.MetaAnnotated.of(element, name, environment);
@Nullable MetaAnnotated existing = cache.putIfAbsent(name, metaAnnotated);
if (existing != null) {
metaAnnotated = existing;
}
}
return metaAnnotated;
}
}
abstract static class Diagnosable {
/**
* Element suitable for reporting as a source of declaration which might causing problems.
*/
@Value.Auxiliary
abstract Element element();
@Value.Auxiliary
abstract Environment environment();
ProcessingEnvironment processing() {
return environment().processing();
}
@Value.Auxiliary
@Value.Derived
public String simpleName() {
return element().getSimpleName().toString();
}
public Reporter report() {
return Reporter.from(processing()).withElement(element());
}
}
@Value.Immutable
public abstract static class Environment {
@Value.Parameter
abstract ProcessingEnvironment processing();
@Value.Parameter
abstract Round round();
@Value.Derived
StyleInfo defaultStyles() {
@Nullable TypeElement element = findElement(StyleMirror.qualifiedName());
if (element == null) {
processing().getMessager()
.printMessage(Diagnostic.Kind.MANDATORY_WARNING,
"Could not found annotations on the compile classpath. It looks like annotation processor is running"
+ " in a separate annotation-processing classpath and unable to get to annotation definitions."
+ " To fix this, please add annotation-only artifact 'org.immutables:value:(version):annotations'"
+ " to 'compile' 'compileOnly' or 'provided' dependency scope.");
element = findElement(StyleMirror.mirrorQualifiedName());
verify(element != null, "Classpath should contain at least mirror annotation, otherwise library is corrupted");
}
try {
return ToStyleInfo.FUNCTION.apply(StyleMirror.from(element));
} catch (Exception ex) {
processing().getMessager()
.printMessage(Diagnostic.Kind.MANDATORY_WARNING,
"The version of the Immutables annotation on the classpath has incompatible differences"
+ " from the Immutables annotation processor used. Various problems might occur,"
+ " like this one: "
+ ex);
element = findElement(StyleMirror.mirrorQualifiedName());
verify(element != null,
"classpath should contain at least the mirror annotation, otherwise library is corrupted");
return ToStyleInfo.FUNCTION.apply(StyleMirror.from(element));
}
}
/**
* @return current Guava's MoreObjects or {@code null} if no Guava available on the classpath.
*/
@Nullable
@Value.Lazy
String typeMoreObjects() {
String typeMoreObjects = UnshadeGuava.typeString("base.MoreObjects");
String typeObjects = UnshadeGuava.typeString("base.Objects");
if (findElement(typeMoreObjects) != null) {
return typeMoreObjects;
}
if (findElement(typeMoreObjects) != null) {
return typeObjects;
}
return null;
}
public boolean hasGuavaLib() {
return typeMoreObjects() != null;
}
@Value.Lazy
public boolean hasOkJsonLib() {
return findElement("com.squareup.moshi.Moshi") != null;
}
@Value.Lazy
public boolean hasGsonLib() {
return findElement("com.google.gson.Gson") != null;
}
@Value.Lazy
public boolean hasJacksonLib() {
return findElement(Proto.JACKSON_DESERIALIZE) != null;
}
@Value.Lazy
public boolean hasMongoModule() {
return findElement(RepositoryMirror.qualifiedName()) != null;
}
@Value.Lazy
public boolean hasSerialModule() {
return findElement(VersionMirror.qualifiedName()) != null;
}
@Value.Lazy
public boolean hasTreesModule() {
return findElement(TransformMirror.qualifiedName()) != null;
}
@Value.Lazy
public boolean hasAstModule() {
return findElement(AstMirror.qualifiedName()) != null;
}
@Value.Lazy
public boolean hasOrdinalModule() {
return findElement(ORDINAL_VALUE_INTERFACE_TYPE) != null;
}
@Value.Lazy
public boolean hasBuilderModule() {
return findElement(FactoryMirror.qualifiedName()) != null;
}
@Value.Lazy
public boolean hasFuncModule() {
return findElement(FunctionalMirror.qualifiedName()) != null;
}
@Value.Lazy
public boolean hasEncodeModule() {
return findElement(EncodingMirror.qualifiedName()) != null;
}
/**
* Default type adapters should only be called if {@code Gson.TypeAdapters} annotation is
* definitely in classpath. Currenlty, it is called by for mongo repository module,
* which have {@code gson} module as a transitive dependency.
* @return default type adapters
*/
@Value.Lazy
TypeAdaptersMirror defaultTypeAdapters() {
@Nullable TypeElement typeElement =
findElement(TypeAdaptersMirror.qualifiedName());
Preconditions.checkState(typeElement != null,
"Processor internal error, @%s is not know to be on the classpath",
TypeAdaptersMirror.qualifiedName());
return TypeAdaptersMirror.from(typeElement);
}
ValueType composeValue(Protoclass protoclass) {
return round().composeValue(protoclass);
}
ImmutableList<Protoclass> protoclassesFrom(Iterable<? extends Element> elements) {
return round().protoclassesFrom(elements);
}
private @Nullable TypeElement findElement(String qualifiedName) {
if (ClasspathFence.isInhibited(qualifiedName)) {
return null;
}
try {
TypeElement typeElement = processing()
.getElementUtils()
.getTypeElement(qualifiedName);
return typeElement;
} catch (Exception ex) {
// to be visible during build
ex.printStackTrace();
// any type loading problems, which are unlikely (leftover?)
return null;
}
}
private final Map<Set<EncodingInfo>, Instantiator> instantiators = new HashMap<>();
Instantiator instantiatorFor(Set<EncodingInfo> encodings) {
@Nullable Instantiator instantiator = instantiators.get(encodings);
if (instantiator == null) {
instantiator = ENCODING_INFLATER.instantiatorFor(encodings);
instantiators.put(encodings, instantiator);
}
return instantiator;
}
}
/**
* Introspection supertype for the {@link DeclaringType} and {@link DeclaringPackage}
*/
public static abstract class AbstractDeclaring extends Diagnosable {
public abstract String name();
public abstract DeclaringPackage packageOf();
@Value.Lazy
protected Optional<IncludeMirror> include() {
return IncludeMirror.find(element());
}
@Value.Lazy
protected Optional<FIncludeMirror> builderInclude() {
return FIncludeMirror.find(element());
}
public String asPrefix() {
return name().isEmpty() ? "" : (name() + ".");
}
public Optional<DeclaringType> asType() {
return this instanceof DeclaringType
? Optional.of((DeclaringType) this)
: Optional.<DeclaringType>absent();
}
/**
* used to intern packaged created internally
*/
@Value.Auxiliary
abstract Proto.Interning interner();
@Value.Lazy
public Optional<TypeAdaptersMirror> typeAdapters() {
return TypeAdaptersMirror.find(element());
}
@Value.Lazy
public Optional<OkTypeAdaptersMirror> okTypeAdapters() {
return OkTypeAdaptersMirror.find(element());
}
@Value.Lazy
List<TypeElement> includedTypes() {
Optional<IncludeMirror> includes = include();
ImmutableList<TypeMirror> typeMirrors = includes.isPresent()
? ImmutableList.copyOf(includes.get().valueMirror())
: ImmutableList.<TypeMirror>of();
FluentIterable<TypeElement> typeElements = FluentIterable.from(typeMirrors)
.filter(DeclaredType.class)
.transform(DeclatedTypeToElement.FUNCTION);
ImmutableSet<String> uniqueTypeNames = typeElements
.filter(IsPublic.PREDICATE)
.transform(ElementToName.FUNCTION)
.toSet();
if (uniqueTypeNames.size() != typeMirrors.size()) {
report().annotationNamed(IncludeMirror.simpleName())
.warning("Some types were ignored, non-supported for inclusion: duplicates,"
+ " non declared reference types, non-public");
}
return typeElements.toList();
}
@Value.Lazy
List<TypeElement> builderIncludedTypes() {
Optional<FIncludeMirror> includes = builderInclude();
ImmutableList<TypeMirror> typeMirrors = includes.isPresent()
? ImmutableList.copyOf(includes.get().valueMirror())
: ImmutableList.<TypeMirror>of();
FluentIterable<TypeElement> typeElements = FluentIterable.from(typeMirrors)
.filter(DeclaredType.class)
.transform(DeclatedTypeToElement.FUNCTION);
ImmutableSet<String> uniqueTypeNames = typeElements
.filter(IsPublic.PREDICATE)
.transform(ElementToName.FUNCTION)
.toSet();
if (uniqueTypeNames.size() != typeMirrors.size()) {
report().annotationNamed(IncludeMirror.simpleName())
.warning("Some types were ignored, non-supported for inclusion: duplicates,"
+ " non declared reference types, non-public");
}
return typeElements.toList();
}
@Value.Lazy
List<MetaAnnotated> metaAnnotated() {
ImmutableList.Builder<MetaAnnotated> builder = ImmutableList.builder();
for (AnnotationMirror mirror : element().getAnnotationMirrors()) {
builder.add(MetaAnnotated.from(mirror, environment()));
}
return builder.build();
}
@Value.Lazy
public Optional<StyleInfo> style() {
Optional<StyleInfo> style = StyleMirror.find(element()).transform(ToStyleInfo.FUNCTION);
if (style.isPresent()) {
return style;
}
for (MetaAnnotated m : metaAnnotated()) {
Optional<StyleInfo> metaStyle = m.style();
if (metaStyle.isPresent()) {
return metaStyle;
}
}
return Optional.absent();
}
@Value.Lazy
public Optional<Long> serialVersion() {
Optional<VersionMirror> version = VersionMirror.find(element());
if (version.isPresent()) {
return Optional.of(version.get().value());
}
for (MetaAnnotated metaAnnotated : metaAnnotated()) {
Optional<Long> serialVersion = metaAnnotated.serialVersion();
if (serialVersion.isPresent()) {
return serialVersion;
}
}
return Optional.<Long>absent();
}
@Value.Lazy
public boolean isSerialStructural() {
return StructuralMirror.isPresent(element());
}
@Value.Lazy
public boolean isJacksonSerialized() {
if (jacksonSerializeMode() == JacksonMode.DELEGATED) {
// while DeclaringPackage cannot have those annotations
// directly, just checking them as a general computation path
// will not hurt much.
return true;
}
for (MetaAnnotated metaAnnotated : metaAnnotated()) {
if (metaAnnotated.isJacksonSerialized()) {
return true;
}
}
return false;
}
@Value.Lazy
public JacksonMode jacksonSerializeMode() {
return Proto.isJacksonSerializedAnnotated(element())
? JacksonMode.DELEGATED
: JacksonMode.NONE;
}
@Value.Lazy
public boolean isJacksonDeserialized() {
if (isJacksonDeserializedAnnotated()) {
// while DeclaringPackage cannot have those annotations
// directly, just checking them as a general computation path
// will not hurt much.
return true;
}
for (MetaAnnotated metaAnnotated : metaAnnotated()) {
if (metaAnnotated.isJacksonDeserialized()) {
return true;
}
}
return false;
}
protected void collectEncodings(Collection<EncodingInfo> encodings) {
for (MetaAnnotated m : metaAnnotated()) {
encodings.addAll(m.encodings());
}
}
@Value.Lazy
public Optional<String[]> depluralize() {
@Nullable String[] dictionary = null;
for (MetaAnnotated metaAnnotated : metaAnnotated()) {
Optional<String[]> depluralize = metaAnnotated.depluralize();
if (depluralize.isPresent()) {
dictionary = concat(dictionary, depluralize.get());
}
}
Optional<DepluralizeMirror> depluralize = DepluralizeMirror.find(element());
if (depluralize.isPresent()) {
dictionary = concat(dictionary, depluralize.get().dictionary());
}
return Optional.fromNullable(dictionary);
}
@Value.Lazy
public boolean isJacksonDeserializedAnnotated() {
return Proto.isJacksonDeserializedAnnotated(element());
}
@Value.Lazy
public boolean isJacksonJsonTypeInfo() {
if (isJacksonJsonTypeInfoAnnotated(element())) {
// while DeclaringPackage cannot have those annotations
// directly, just checking them as a general computation path
// will not hurt much.
return true;
}
for (MetaAnnotated metaAnnotated : metaAnnotated()) {
if (metaAnnotated.isJacksonJsonTypeInfo()) {
return true;
}
}
return false;
}
}
public enum JacksonMode {
NONE, DELEGATED, BUILDER;
}
@Value.Immutable
public static abstract class DeclaringPackage extends AbstractDeclaring {
@Override
@Value.Auxiliary
public abstract PackageElement element();
@Override
public DeclaringPackage packageOf() {
return this;
}
@Override
@Value.Auxiliary
@Value.Derived
public String simpleName() {
return element().isUnnamed() ? "" : element().getSimpleName().toString();
}
/**
* Name is the only equivalence attribute. Basically packages are interned by name.
* @return package name
*/
@Override
@Value.Derived
public String name() {
return element().isUnnamed() ? "" : element().getQualifiedName().toString();
}
@Value.Lazy
Optional<DeclaringPackage> namedParentPackage() {
String parentPackageName = SourceNames.parentPackageName(element());
if (!parentPackageName.isEmpty()) {
@Nullable PackageElement parentPackage =
environment().processing()
.getElementUtils()
.getPackageElement(parentPackageName);
if (parentPackage != null) {
return Optional.of(interner().forPackage(
ImmutableProto.DeclaringPackage.builder()
.environment(environment())
.interner(interner())
.element(parentPackage)
.build()));
}
}
return Optional.absent();
}
@Override
@Value.Lazy
public boolean isJacksonSerialized() {
boolean isJacksonSerialized = super.isJacksonSerialized();
if (isJacksonSerialized) {
return isJacksonSerialized;
}
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
return parent.get().isJacksonSerialized();
}
return false;
}
@Override
@Value.Lazy
public boolean isJacksonDeserialized() {
if (super.isJacksonDeserialized()) {
return true;
}
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
return parent.get().isJacksonDeserialized();
}
return false;
}
@Override
@Value.Lazy
public boolean isJacksonJsonTypeInfo() {
if (super.isJacksonJsonTypeInfo()) {
return true;
}
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
return parent.get().isJacksonJsonTypeInfo();
}
return false;
}
@Override
@Value.Lazy
public boolean isSerialStructural() {
boolean isSerialStructural = super.isSerialStructural();
if (isSerialStructural) {
return isSerialStructural;
}
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
return parent.get().isSerialStructural();
}
return false;
}
@Override
@Value.Lazy
public Optional<Long> serialVersion() {
Optional<Long> serialVersion = super.serialVersion();
if (serialVersion.isPresent()) {
return serialVersion;
}
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
return parent.get().serialVersion();
}
return Optional.absent();
}
@Override
@Value.Lazy
public Optional<StyleInfo> style() {
Optional<StyleInfo> style = super.style();
if (style.isPresent()) {
return style;
}
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
return parent.get().style();
}
return Optional.absent();
}
@Override
@Value.Lazy
public Optional<String[]> depluralize() {
@Nullable String[] dictionary = null;
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
Optional<String[]> depluralize = parent.get().depluralize();
if (depluralize.isPresent()) {
dictionary = concat(dictionary, depluralize.get());
}
}
Optional<String[]> depluralize = super.depluralize();
if (depluralize.isPresent()) {
dictionary = concat(dictionary, depluralize.get());
}
return Optional.fromNullable(dictionary);
}
@Override
protected void collectEncodings(Collection<EncodingInfo> encodings) {
Optional<DeclaringPackage> parent = namedParentPackage();
if (parent.isPresent()) {
parent.get().collectEncodings(encodings);
}
super.collectEncodings(encodings);
}
}
@Value.Immutable
public static abstract class DeclaringType extends AbstractDeclaring {
@Override
@Value.Auxiliary
public abstract TypeElement element();
@Override
@Value.Derived
public String name() {
return element().getQualifiedName().toString();
}
/**
* returns this class if it's top level or enclosing top level type.
* @return accossiated top level type.
*/
public DeclaringType associatedTopLevel() {
return enclosingTopLevel().or(this);
}
@Value.Lazy
public Optional<DeclaringType> enclosingTopLevel() {
TypeElement top = element();
for (Element e = top; e.getKind() != ElementKind.PACKAGE; e = e.getEnclosingElement()) {
top = (TypeElement) e;
}
if (top == element()) {
return Optional.absent();
}
return Optional.of(interner().forType(
ImmutableProto.DeclaringType.builder()
.environment(environment())
.interner(interner())
.element(top)
.build()));
}
@Value.Lazy
public Optional<RepositoryMirror> repository() {
return RepositoryMirror.find(element());
}
@Value.Lazy
public Optional<DeclaringType> enclosingOf() {
Optional<DeclaringType> topLevel = enclosingTopLevel();
if (topLevel.isPresent() && topLevel.get().isEnclosing()) {
return topLevel;
}
return Optional.absent();
}
@Override
@Value.Derived
@Value.Auxiliary
public DeclaringPackage packageOf() {
Element e = element();
for (; e.getKind() != ElementKind.PACKAGE; e = e.getEnclosingElement()) {
}
return interner().forPackage(
ImmutableProto.DeclaringPackage.builder()
.environment(environment())
.interner(interner())
.element((PackageElement) e)
.build());
}
@Value.Lazy
public Optional<ValueImmutableInfo> features() {
Optional<ValueImmutableInfo> immutableAnnotation =
ImmutableMirror.find(element()).transform(ToImmutableInfo.FUNCTION);
if (immutableAnnotation.isPresent()) {
return immutableAnnotation;
}
for (String a : environment().round().customImmutableAnnotations()) {
if (isAnnotatedWith(element(), a)) {
return Optional.of(environment().defaultStyles().defaults());
}
}
return Optional.absent();
}
@Value.Lazy
@Override
public JacksonMode jacksonSerializeMode() {
boolean wasJacksonSerialize = false;
for (AnnotationMirror a : element().getAnnotationMirrors()) {
TypeElement e = (TypeElement) a.getAnnotationType().asElement();
if (!wasJacksonSerialize && e.getQualifiedName().contentEquals(JACKSON_SERIALIZE)) {
wasJacksonSerialize = true;
}
if (e.getQualifiedName().contentEquals(JACKSON_DESERIALIZE)) {
for (ExecutableElement attr : a.getElementValues().keySet()) {
if (attr.getSimpleName().contentEquals("builder")) {
// If builder attribute is specified, we don't consider this as
// our, immutables, business to generate anything.
return JacksonMode.BUILDER;
}
}
return JacksonMode.DELEGATED;
}
}
return wasJacksonSerialize
? JacksonMode.DELEGATED
: JacksonMode.NONE;
}
@Value.Lazy
public boolean useImmutableDefaults() {
Optional<ValueImmutableInfo> immutables = features();
if (immutables.isPresent()) {
return immutables.get().isDefault();
}
return true;
}
@Value.Lazy
public boolean isEnclosing() {
if (EnclosingMirror.isPresent(element())) {
return true;
}
if (isTopLevel()) {
for (MetaAnnotated metaAnnotated : metaAnnotated()) {
if (metaAnnotated.isEnclosing()) {
return true;
}
}
}
return false;
}
@Value.Lazy
public boolean isModifiable() {
return ModifiableMirror.isPresent(element());
}
/**
* @return true, if is top level
*/
@Value.Derived
@Value.Auxiliary
public boolean isTopLevel() {
return element().getNestingKind() == NestingKind.TOP_LEVEL;
}
public boolean isImmutable() {
return features().isPresent();
}
boolean verifiedFactory(ExecutableElement element) {
if (!isTopLevel() || !suitableForBuilderFactory(element)) {
report().withElement(element)
.annotationNamed(FactoryMirror.simpleName())
.error("@%s method '%s' should be static, non-private, non-void and enclosed in top level type",
FactoryMirror.simpleName(),
element.getSimpleName());
return false;
}
return true;
}
boolean verifiedConstructor(ExecutableElement element) {
if (!isTopLevel() || !suitableForBuilderConstructor(element)) {
report().withElement(element)
.annotationNamed(FConstructorMirror.simpleName())
.error("@%s annotated element should be non-private constructor in a top level type",
FConstructorMirror.simpleName(),
element.getSimpleName());
return false;
}
return true;
}
static boolean suitableForBuilderConstructor(ExecutableElement element) {
return element.getKind() == ElementKind.CONSTRUCTOR
&& !element.getModifiers().contains(Modifier.PRIVATE);
}
static boolean suitableForBuilderFactory(ExecutableElement element) {
return element.getKind() == ElementKind.METHOD
&& element.getReturnType().getKind() != TypeKind.VOID
&& !element.getModifiers().contains(Modifier.PRIVATE)
&& element.getModifiers().contains(Modifier.STATIC);
}
/**
* Some validations, not exhaustive.
*/
@Value.Check
protected void validate() {
if (include().isPresent() && !isTopLevel()) {
report()
.annotationNamed(IncludeMirror.simpleName())
.error("@%s could not be used on nested types.", IncludeMirror.simpleName());
}
if (builderInclude().isPresent() && !isTopLevel()) {
report()
.annotationNamed(FIncludeMirror.simpleName())
.error("@%s could not be used on nested types.", FIncludeMirror.simpleName());
}
if (isEnclosing() && !isTopLevel()) {
report()
.annotationNamed(EnclosingMirror.simpleName())
.error("@%s should only be used on a top-level types.", EnclosingMirror.simpleName());
}
if (isImmutable() && element().getKind() == ElementKind.ENUM) {
report()
.annotationNamed(ImmutableMirror.simpleName())
.error("@%s is not supported on enums", ImmutableMirror.simpleName());
}
if (isModifiable() && (isEnclosed() || isEnclosing())) {
report()
.annotationNamed(ModifiableMirror.simpleName())
.error("@%s could not be used with or within @%s",
ModifiableMirror.simpleName(),
EnclosingMirror.simpleName());
}
}
@Value.Lazy
public CharSequence sourceCode() {
if (!isTopLevel()) {
return associatedTopLevel().sourceCode();
}
return SourceExtraction.extract(processing(), CachingElements.getDelegate(element()));
}
@Value.Lazy
public CharSequence headerComments() {
if (!isTopLevel()) {
return associatedTopLevel().headerComments();
}
return SourceExtraction.headerFrom(sourceCode());
}
@Value.Lazy
public SourceExtraction.Imports sourceImports() {
if (!isTopLevel()) {
return associatedTopLevel().sourceImports();
}
return SourceExtraction.importsFrom(sourceCode());
}
public boolean isTransformer() {
return getTransform().isPresent();
}
public boolean isVisitor() {
return getVisit().isPresent();
}
@Value.Lazy
public Optional<TransformMirror> getTransform() {
return environment().hasTreesModule()
? TransformMirror.find(element())
: Optional.<TransformMirror>absent();
}
@Value.Lazy
public Optional<TreesIncludeMirror> getTreesInclude() {
return environment().hasTreesModule()
? TreesIncludeMirror.find(element())
: Optional.<TreesIncludeMirror>absent();
}
@Value.Lazy
public Optional<VisitMirror> getVisit() {
return environment().hasTreesModule()
? VisitMirror.find(element())
: Optional.<VisitMirror>absent();
}
@Value.Lazy
public boolean isAst() {
// considering ast is still in tree module
return environment().hasTreesModule()
&& AstMirror.isPresent(element());
}
public boolean isEnclosed() {
return enclosingOf().isPresent();
}
@Override
protected void collectEncodings(Collection<EncodingInfo> encodings) {
if (enclosingTopLevel().isPresent()) {
enclosingTopLevel().get().collectEncodings(encodings);
}
super.collectEncodings(encodings);
}
}
/**
* Prototypical model for generated derived classes. {@code Protoclass} could be used to projects
* different kind of derived classes.
*/
@Value.Immutable
public static abstract class Protoclass extends Diagnosable {
@Value.Derived
public String name() {
return SourceNames.sourceQualifiedNameFor(sourceElement());
}
/**
* Source type elements stores type element which is used as a source of value type model.
* It is the annotated class for {@code @Value.Immutable} or type referenced in
* {@code @Value.Include}.
* @return source element
*/
@Value.Auxiliary
public abstract Element sourceElement();
/**
* Declaring package that defines value type (usually by import).
* Or the package in which {@link #declaringType()} resides.
* @return declaring package
*/
public abstract DeclaringPackage packageOf();
/**
* The class, which is annotated to be a {@code @Value.Immutable}, {@code @Value.Include} or
* {@code @Value.Enclosing}.
* @return declaring type
*/
public abstract Optional<DeclaringType> declaringType();
@Value.Lazy
public Optional<RepositoryMirror> repository() {
if (!declaringType().isPresent()) {
return Optional.absent();
}
Optional<RepositoryMirror> repositoryMirror =
kind().isIncluded() || kind().isDefinedValue()
? declaringType().get().repository()
: Optional.<RepositoryMirror>absent();
if (repositoryMirror.isPresent() && !typeAdaptersProvider().isPresent()) {
if (kind().isNested()) {
report().annotationNamed(RepositoryMirror.simpleName())
.error("@Mongo.%s should also have associated @Gson.%s on a top level type.",
RepositoryMirror.simpleName(),
TypeAdaptersMirror.simpleName());
} else {
report().annotationNamed(RepositoryMirror.simpleName())
.warning("@Mongo.%s types better have explicit @Gson.%s annotation"
+ " be placed on the class or enclosing package."
+ " It is also common to forget to generate type adapters"
+ " for nested document classes, which will fallback to reflective Gson adapter otherwise.",
RepositoryMirror.simpleName(),
TypeAdaptersMirror.simpleName());
}
}
return repositoryMirror;
}
@Value.Lazy
public Optional<TypeAdaptersMirror> gsonTypeAdapters() {
Optional<AbstractDeclaring> typeAdaptersProvider = typeAdaptersProvider();
if (typeAdaptersProvider.isPresent()) {
return typeAdaptersProvider.get().typeAdapters();
}
if ((kind().isDefinedValue() || kind().isIncluded())
&& !kind().isNested()
&& repository().isPresent()) {
return Optional.of(environment().defaultTypeAdapters());
}
return Optional.absent();
}
@Value.Lazy
public Optional<AbstractDeclaring> typeAdaptersProvider() {
Optional<DeclaringType> typeDefining =
declaringType().isPresent()
? Optional.of(declaringType().get().associatedTopLevel())
: Optional.<DeclaringType>absent();
Optional<TypeAdaptersMirror> typeDefined =
typeDefining.isPresent()
? typeDefining.get().typeAdapters()
: Optional.<TypeAdaptersMirror>absent();
Optional<TypeAdaptersMirror> packageDefined = packageOf().typeAdapters();
if (packageDefined.isPresent()) {
if (typeDefined.isPresent()) {
report()
.withElement(typeDefining.get().element())
.annotationNamed(TypeAdaptersMirror.simpleName())
.warning("@%s is also used on the package, this type level annotation is ignored",
TypeAdaptersMirror.simpleName());
}
return Optional.<AbstractDeclaring>of(packageOf());
}
return typeDefined.isPresent()
? Optional.<AbstractDeclaring>of(typeDefining.get())
: Optional.<AbstractDeclaring>absent();
}
@Value.Lazy
public Optional<OkTypeAdaptersMirror> okJsonTypeAdapters() {
Optional<AbstractDeclaring> typeAdaptersProvider = okTypeAdaptersProvider();
if (typeAdaptersProvider.isPresent()) {
return typeAdaptersProvider.get().okTypeAdapters();
}
return Optional.absent();
}
@Value.Lazy
public Optional<AbstractDeclaring> okTypeAdaptersProvider() {
Optional<DeclaringType> typeDefining =
declaringType().isPresent()
? Optional.of(declaringType().get().associatedTopLevel())
: Optional.<DeclaringType>absent();
Optional<OkTypeAdaptersMirror> typeDefined =
typeDefining.isPresent()
? typeDefining.get().okTypeAdapters()
: Optional.<OkTypeAdaptersMirror>absent();
Optional<OkTypeAdaptersMirror> packageDefined = packageOf().okTypeAdapters();
if (packageDefined.isPresent()) {
if (typeDefined.isPresent()) {
report()
.withElement(typeDefining.get().element())
.annotationNamed(OkTypeAdaptersMirror.simpleName())
.warning("@%s is also used on the package, this type level annotation is ignored",
OkTypeAdaptersMirror.simpleName());
}
return Optional.<AbstractDeclaring>of(packageOf());
}
return typeDefined.isPresent()
? Optional.<AbstractDeclaring>of(typeDefining.get())
: Optional.<AbstractDeclaring>absent();
}
/**
* Kind of protoclass declaration, it specifies how exactly the protoclass was declared.
* @return definition kind
*/
public abstract Kind kind();
@Value.Derived
public Visibility visibility() {
return Visibility.of(sourceElement());
}
public Visibility declaringVisibility() {
if (declaringType().isPresent()) {
return Visibility.of(declaringType().get().element());
}
return Visibility.PUBLIC;
}
/**
* Element used mostly for error reporting,
* real model provided by {@link #sourceElement()}.
*/
@Value.Derived
@Value.Auxiliary
@Override
public Element element() {
if (kind().isFactory()) {
return sourceElement();
}
if (declaringType().isPresent()) {
return declaringType().get().element();
}
return packageOf().element();
}
@Value.Lazy
public Optional<Long> serialVersion() {
if (declaringType().isPresent()) {
DeclaringType t = declaringType().get();
if (t.serialVersion().isPresent()) {
return t.serialVersion();
}
if (t.enclosingTopLevel().isPresent()) {
if (t.enclosingTopLevel().get().serialVersion().isPresent()) {
return t.enclosingTopLevel().get().serialVersion();
}
}
}
return packageOf().serialVersion();
}
@Value.Lazy
public boolean isSerialStructural() {
if (declaringType().isPresent()) {
DeclaringType t = declaringType().get();
if (t.isSerialStructural()) {
return true;
}
if (t.enclosingTopLevel().isPresent()) {
if (t.enclosingTopLevel().get().isSerialStructural()) {
return true;
}
}
}
return packageOf().isSerialStructural();
}
@Value.Lazy
public boolean isJacksonSerialized() {
if (!styles().style().jacksonIntegration()) {
return false;
}
if (declaringType().isPresent()) {
DeclaringType t = declaringType().get();
if (t.isJacksonSerialized()) {
return true;
}
if (t.enclosingTopLevel().isPresent()) {
if (t.enclosingTopLevel().get().isJacksonSerialized()) {
return true;
}
}
}
return packageOf().isJacksonSerialized();
}
@Value.Lazy
public boolean isJacksonDeserialized() {
if (!styles().style().jacksonIntegration()) {
return false;
}
if (declaringType().isPresent()) {
DeclaringType t = declaringType().get();
if (t.isJacksonDeserialized()) {
return true;
}
if (t.enclosingTopLevel().isPresent()) {
if (t.enclosingTopLevel().get().isJacksonDeserialized()) {
return true;
}
}
}
return packageOf().isJacksonDeserialized();
}
@Value.Lazy
public ValueImmutableInfo features() {
if (declaringType().isPresent()
&& !declaringType().get().useImmutableDefaults()) {
Optional<ValueImmutableInfo> features = declaringType().get().features();
if (features.isPresent()) {
return features.get();
}
}
return styles().defaults();
}
@Value.Lazy
public Styles styles() {
StyleInfo styleInfo = determineStyle().or(environment().defaultStyles());
Optional<String[]> depluralize = depluralize();
if (depluralize.isPresent()) {
styleInfo = ImmutableStyleInfo.copyOf(styleInfo)
.withDepluralize(true)
.withDepluralizeDictionary(concat(styleInfo.depluralizeDictionary(), depluralize.get()));
}
return styleInfo.getStyles();
}
@Value.Lazy
public Optional<String[]> depluralize() {
@Nullable String[] dictionary = null;
Optional<String[]> depluralize = packageOf().depluralize();
if (depluralize.isPresent()) {
dictionary = concat(dictionary, depluralize.get());
}
if (declaringType().isPresent()) {
DeclaringType type = declaringType().get();
if (type.enclosingTopLevel().isPresent()) {
depluralize = type.enclosingTopLevel().get().depluralize();
if (depluralize.isPresent()) {
dictionary = concat(dictionary, depluralize.get());
}
}
depluralize = type.depluralize();
if (depluralize.isPresent()) {
dictionary = concat(dictionary, depluralize.get());
}
}
return Optional.fromNullable(dictionary);
}
private Optional<StyleInfo> determineStyle() {
if (declaringType().isPresent()) {
DeclaringType type = declaringType().get();
Optional<DeclaringType> enclosing = type.enclosingOf();
if (enclosing.isPresent()) {
Optional<StyleInfo> enclosingStyle = enclosing.get().style();
if (enclosing.get() != type) {
Optional<StyleInfo> style = type.style();
if (style.isPresent()
&& enclosingStyle.isPresent()
&& !style.equals(enclosingStyle)) {
warnAboutIncompatibleStyles();
}
}
if (enclosingStyle.isPresent()) {
return enclosingStyle;
}
} else {
Optional<StyleInfo> style = type.style();
if (style.isPresent()) {
return style;
}
Optional<DeclaringType> topLevel = type.enclosingTopLevel();
if (topLevel.isPresent() && topLevel.get().style().isPresent()) {
return topLevel.get().style();
}
}
}
return packageOf().style();
}
private void warnAboutIncompatibleStyles() {
report().annotationNamed(StyleMirror.simpleName())
.warning("Use styles only on enclosing types."
+ " All nested styles will inherit it."
+ " Nested immutables cannot deviate in style from enclosing type,"
+ " so generated stucture will be consistent");
}
@Value.Derived
@Value.Auxiliary
public Optional<DeclaringType> enclosingOf() {
if (declaringType().isPresent()) {
if (kind().isFactory()) {
return declaringType();
}
if (kind().isNested()) {
if (kind().isIncluded()) {
return declaringType();
}
return declaringType().get().enclosingOf();
}
}
return Optional.absent();
}
TypeNames createTypeNames() {
Element sourceElement = sourceElement();
if (sourceElement.getKind() == ElementKind.CONSTRUCTOR) {
sourceElement = sourceElement.getEnclosingElement();
}
return styles().forType(sourceElement.getSimpleName().toString());
}
public enum Kind {
INCLUDED_IN_PACKAGE,
INCLUDED_ON_TYPE,
INCLUDED_FACTORY_IN_PACKAGE,
INCLUDED_FACTORY_ON_TYPE,
INCLUDED_CONSTRUCTOR_IN_PACKAGE,
INCLUDED_CONSTRUCTOR_ON_TYPE,
INCLUDED_IN_TYPE,
DEFINED_FACTORY,
DEFINED_CONSTRUCTOR,
DEFINED_TYPE,
DEFINED_TYPE_AND_COMPANION,
DEFINED_COMPANION,
DEFINED_AND_ENCLOSING_TYPE,
DEFINED_ENCLOSING_TYPE,
DEFINED_NESTED_TYPE;
public boolean isNested() {
switch (this) {
case INCLUDED_IN_TYPE:
case DEFINED_NESTED_TYPE:
return true;
default:
return false;
}
}
public boolean isIncluded() {
switch (this) {
case INCLUDED_IN_PACKAGE:
case INCLUDED_IN_TYPE:
case INCLUDED_ON_TYPE:
return true;
default:
return false;
}
}
public boolean isEnclosing() {
switch (this) {
case DEFINED_AND_ENCLOSING_TYPE:
case DEFINED_ENCLOSING_TYPE:
return true;
default:
return false;
}
}
public boolean isValue() {
switch (this) {
case INCLUDED_IN_PACKAGE:
case INCLUDED_ON_TYPE:
case INCLUDED_IN_TYPE:
case DEFINED_TYPE:
case DEFINED_TYPE_AND_COMPANION:
case DEFINED_AND_ENCLOSING_TYPE:
case DEFINED_NESTED_TYPE:
return true;
default:
return false;
}
}
public boolean isDefinedValue() {
switch (this) {
case DEFINED_TYPE:
case DEFINED_TYPE_AND_COMPANION:
case DEFINED_AND_ENCLOSING_TYPE:
case DEFINED_NESTED_TYPE:
return true;
default:
return false;
}
}
public boolean isModifiable() {
return this == DEFINED_TYPE_AND_COMPANION
|| this == DEFINED_COMPANION;
}
public boolean isConstructor() {
switch (this) {
case DEFINED_CONSTRUCTOR:
case INCLUDED_CONSTRUCTOR_IN_PACKAGE:
case INCLUDED_CONSTRUCTOR_ON_TYPE:
return true;
default:
return false;
}
}
public boolean isFactory() {
switch (this) {
case DEFINED_FACTORY:
case INCLUDED_FACTORY_IN_PACKAGE:
case INCLUDED_FACTORY_ON_TYPE:
case DEFINED_CONSTRUCTOR:
case INCLUDED_CONSTRUCTOR_IN_PACKAGE:
case INCLUDED_CONSTRUCTOR_ON_TYPE:
return true;
default:
return false;
}
}
public boolean isEnclosingOnly() {
return this == DEFINED_ENCLOSING_TYPE;
}
}
@Value.Lazy
public boolean isJacksonJsonTypeInfo() {
if (!styles().style().jacksonIntegration()) {
return false;
}
if (declaringType().isPresent()) {
DeclaringType type = declaringType().get();
if (type.isJacksonJsonTypeInfo()) {
return true;
}
}
return packageOf().isJacksonJsonTypeInfo();
}
public boolean isAst() {
return declaringType().isPresent()
&& declaringType().get().isAst();
}
public boolean isTransformer() {
return declaringType().isPresent()
&& declaringType().get().isTransformer();
}
public boolean isVisitor() {
return declaringType().isPresent()
&& declaringType().get().isVisitor();
}
public Optional<TransformMirror> getTransform() {
return declaringType().isPresent()
? declaringType().get().getTransform()
: Optional.<TransformMirror>absent();
}
public Optional<VisitMirror> getVisit() {
return declaringType().isPresent()
? declaringType().get().getVisit()
: Optional.<VisitMirror>absent();
}
public Optional<TreesIncludeMirror> getTreesInclude() {
return declaringType().isPresent()
? declaringType().get().getTreesInclude()
: Optional.<TreesIncludeMirror>absent();
}
@Value.Lazy
public Constitution constitution() {
return ImmutableConstitution.builder()
.protoclass(this)
.build();
}
@Value.Lazy
public Instantiator encodingInstantiator() {
List<EncodingInfo> results = new ArrayList<>();
packageOf().collectEncodings(results);
if (declaringType().isPresent()) {
declaringType().get().collectEncodings(results);
}
return environment().instantiatorFor(FluentIterable.from(results).toSet());
}
public boolean isJacksonProperties() {
if (!styles().style().jacksonIntegration()) {
return false;
}
if (declaringType().isPresent()) {
if (declaringType().get().jacksonSerializeMode() != JacksonMode.NONE) {
return true;
}
}
return isJacksonSerialized();
}
}
enum ElementToName implements Function<TypeElement, String> {
FUNCTION;
@Override
public String apply(TypeElement input) {
return input.getQualifiedName().toString();
}
}
enum DeclatedTypeToElement implements Function<DeclaredType, TypeElement> {
FUNCTION;
@Override
public TypeElement apply(DeclaredType input) {
return (TypeElement) input.asElement();
}
}
enum IsPublic implements Predicate<Element> {
PREDICATE;
@Override
public boolean apply(Element input) {
return input.getModifiers().contains(Modifier.PUBLIC);
}
}
enum ToImmutableInfo implements Function<ImmutableMirror, ValueImmutableInfo> {
FUNCTION;
@Override
public ValueImmutableInfo apply(ImmutableMirror input) {
return ImmutableValueImmutableInfo.theOf(
input.builder(),
input.copy(),
input.intern(),
input.prehash(),
input.singleton())
.withIsDefault(input.getAnnotationMirror().getElementValues().isEmpty());
}
}
enum ToStyleInfo implements Function<StyleMirror, StyleInfo> {
FUNCTION;
@Override
public StyleInfo apply(StyleMirror input) {
return ImmutableStyleInfo.of(
input.get(),
input.init(),
input.with(),
input.add(),
input.addAll(),
input.put(),
input.putAll(),
input.copyOf(),
input.of(),
input.instance(),
input.builder(),
input.newBuilder(),
input.from(),
input.build(),
input.buildOrThrow(),
input.isInitialized(),
input.isSet(),
input.set(),
input.unset(),
input.clear(),
input.create(),
input.toImmutable(),
input.typeBuilder(),
input.typeInnerBuilder(),
input.typeAbstract(),
input.typeImmutable(),
input.typeImmutableEnclosing(),
input.typeImmutableNested(),
input.typeModifiable(),
input.typeWith(),
input.packageGenerated(),
ToImmutableInfo.FUNCTION.apply(input.defaults()),
input.strictBuilder(),
input.validationMethod(),
input.allParameters(),
input.defaultAsDefault(),
input.headerComments(),
input.jdkOnly(),
ImmutableSet.copyOf(input.passAnnotationsName()),
ImmutableSet.copyOf(input.additionalJsonAnnotationsName()),
input.visibility(),
input.optionalAcceptNullable(),
input.generateSuppressAllWarnings(),
input.privateNoargConstructor(),
input.attributelessSingleton(),
input.unsafeDefaultAndDerived(),
input.clearBuilder(),
input.deferCollectionAllocation(),
input.deepImmutablesDetection(),
input.overshadowImplementation(),
input.implementationNestedInBuilder(),
input.forceJacksonPropertyNames(),
input.forceJacksonIgnoreFields(),
input.jacksonIntegration(),
input.builderVisibility(),
input.throwForInvalidImmutableStateName(),
input.depluralize(),
input.depluralizeDictionary(),
ImmutableSet.copyOf(input.immutableCopyOfRoutinesName()),
input.stagedBuilder(),
input.builtinContainerAttributes(),
input.beanFriendlyModifiables(),
input.allMandatoryParameters(),
input.redactedMask());
}
}
static boolean isJacksonSerializedAnnotated(Element element) {
return isAnnotatedWith(element, JACKSON_SERIALIZE)
|| isAnnotatedWith(element, JACKSON_DESERIALIZE);
}
static boolean isJacksonDeserializedAnnotated(Element element) {
return isAnnotatedWith(element, JACKSON_DESERIALIZE);
}
static boolean isJacksonJsonTypeInfoAnnotated(Element element) {
return isAnnotatedWith(element, JACKSON_TYPE_INFO);
}
static boolean isAnnotatedWith(Element element, String annotation) {
for (AnnotationMirror a : element.getAnnotationMirrors()) {
TypeElement e = (TypeElement) a.getAnnotationType().asElement();
if (e.getQualifiedName().contentEquals(annotation)) {
return true;
}
if (Annotations.hasJacksonPackagePrefix(annotation)
&& !annotation.equals(JACKSON_ANNOTATIONS_INSIDE)
&& isAnnotatedWith(e, JACKSON_ANNOTATIONS_INSIDE)
&& isAnnotatedWith(e, annotation)) {
return true;
}
}
return false;
}
static @Nullable String[] concat(@Nullable String[] first, @Nullable String[] second) {
if (first == null)
return second;
if (second == null)
return first;
return ObjectArrays.concat(first, second, String.class);
}
static final String ORDINAL_VALUE_INTERFACE_TYPE = "org.immutables.ordinal.OrdinalValue";
static final String JACKSON_TYPE_INFO = "com.fasterxml.jackson.annotation.JsonTypeInfo";
static final String JACKSON_DESERIALIZE = "com.fasterxml.jackson.databind.annotation.JsonDeserialize";
static final String JACKSON_SERIALIZE = "com.fasterxml.jackson.databind.annotation.JsonSerialize";
static final String JACKSON_ANNOTATIONS_INSIDE = "com.fasterxml.jackson.annotation.JacksonAnnotationsInside";
static final String PARCELABLE_INTERFACE_TYPE = "android.os.Parcelable";
}