276 lines
11 KiB
Java
276 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2019 The Dagger 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
|
|
*
|
|
* 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 dagger.internal.codegen;
|
|
|
|
import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
|
|
import static com.google.common.base.Preconditions.checkState;
|
|
import static com.google.common.collect.Maps.transformValues;
|
|
import static dagger.internal.codegen.DaggerStreams.toImmutableList;
|
|
import static javax.lang.model.util.ElementFilter.fieldsIn;
|
|
|
|
import com.google.auto.common.MoreTypes;
|
|
import com.google.common.collect.ImmutableList;
|
|
import dagger.internal.codegen.serialization.AnnotationProto;
|
|
import dagger.internal.codegen.serialization.AnnotationValueProto;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import javax.inject.Inject;
|
|
import javax.lang.model.element.AnnotationMirror;
|
|
import javax.lang.model.element.AnnotationValue;
|
|
import javax.lang.model.element.AnnotationValueVisitor;
|
|
import javax.lang.model.element.VariableElement;
|
|
import javax.lang.model.type.TypeMirror;
|
|
import javax.lang.model.util.SimpleAnnotationValueVisitor8;
|
|
|
|
/** Converts {@link AnnotationMirror}s to {@link AnnotationProto}s and vice-versa. */
|
|
final class AnnotationProtoConverter {
|
|
private final TypeProtoConverter typeProtoConverter;
|
|
|
|
@Inject
|
|
AnnotationProtoConverter(TypeProtoConverter typeProtoConverter) {
|
|
this.typeProtoConverter = typeProtoConverter;
|
|
}
|
|
|
|
/** Translates an {@link AnnotationMirror} to a proto representation. */
|
|
static AnnotationProto toProto(AnnotationMirror annotationMirror) {
|
|
AnnotationProto.Builder builder = AnnotationProto.newBuilder();
|
|
builder.setAnnotationType(TypeProtoConverter.toProto(annotationMirror.getAnnotationType()));
|
|
getAnnotationValuesWithDefaults(annotationMirror)
|
|
.forEach(
|
|
(attribute, value) ->
|
|
builder.putAllValues(
|
|
Collections.singletonMap(
|
|
attribute.getSimpleName().toString(), annotationValueProto(value))));
|
|
return builder.build();
|
|
}
|
|
|
|
/** Creates an {@link AnnotationMirror} from its proto representation. */
|
|
AnnotationMirror fromProto(AnnotationProto annotation) {
|
|
return SimpleAnnotationMirror.of(
|
|
MoreTypes.asTypeElement(typeProtoConverter.fromProto(annotation.getAnnotationType())),
|
|
transformValues(annotation.getValues(), AnnotationValueFromProto::new));
|
|
}
|
|
|
|
private static final AnnotationValueVisitor<
|
|
AnnotationValueProto.Builder, AnnotationValueProto.Builder>
|
|
ANNOTATION_VALUE_TO_PROTO =
|
|
new SimpleAnnotationValueVisitor8<
|
|
AnnotationValueProto.Builder, AnnotationValueProto.Builder>() {
|
|
@Override
|
|
public AnnotationValueProto.Builder visitAnnotation(
|
|
AnnotationMirror nestedAnnotation, AnnotationValueProto.Builder builder) {
|
|
return builder
|
|
.setNestedAnnotation(toProto(nestedAnnotation))
|
|
.setKind(AnnotationValueProto.Kind.ANNOTATION);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitBoolean(
|
|
boolean b, AnnotationValueProto.Builder builder) {
|
|
return builder.setBooleanValue(b).setKind(AnnotationValueProto.Kind.BOOLEAN);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitChar(
|
|
char c, AnnotationValueProto.Builder builder) {
|
|
return builder
|
|
.setStringValue(String.valueOf(c))
|
|
.setKind(AnnotationValueProto.Kind.CHAR);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitByte(
|
|
byte b, AnnotationValueProto.Builder builder) {
|
|
return builder.setIntValue(b).setKind(AnnotationValueProto.Kind.BYTE);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitShort(
|
|
short s, AnnotationValueProto.Builder builder) {
|
|
return builder.setIntValue(s).setKind(AnnotationValueProto.Kind.SHORT);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitInt(
|
|
int i, AnnotationValueProto.Builder builder) {
|
|
return builder.setIntValue(i).setKind(AnnotationValueProto.Kind.INT);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitFloat(
|
|
float f, AnnotationValueProto.Builder builder) {
|
|
return builder.setFloatValue(f).setKind(AnnotationValueProto.Kind.FLOAT);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitLong(
|
|
long l, AnnotationValueProto.Builder builder) {
|
|
return builder.setLongValue(l).setKind(AnnotationValueProto.Kind.LONG);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitDouble(
|
|
double d, AnnotationValueProto.Builder builder) {
|
|
return builder.setDoubleValue(d).setKind(AnnotationValueProto.Kind.DOUBLE);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitString(
|
|
String s, AnnotationValueProto.Builder builder) {
|
|
return builder.setStringValue(s).setKind(AnnotationValueProto.Kind.STRING);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitType(
|
|
TypeMirror t, AnnotationValueProto.Builder builder) {
|
|
return builder
|
|
.setClassLiteral(TypeProtoConverter.toProto(t))
|
|
.setKind(AnnotationValueProto.Kind.CLASS_LITERAL);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitEnumConstant(
|
|
VariableElement c, AnnotationValueProto.Builder builder) {
|
|
return builder
|
|
.setEnumType(TypeProtoConverter.toProto(c.asType()))
|
|
.setEnumName(c.getSimpleName().toString())
|
|
.setKind(AnnotationValueProto.Kind.ENUM);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitArray(
|
|
List<? extends AnnotationValue> values, AnnotationValueProto.Builder builder) {
|
|
values.forEach(value -> builder.addArrayValues(annotationValueProto(value)));
|
|
return builder.setKind(AnnotationValueProto.Kind.ARRAY);
|
|
}
|
|
|
|
@Override
|
|
public AnnotationValueProto.Builder visitUnknown(
|
|
AnnotationValue av, AnnotationValueProto.Builder builder) {
|
|
throw new UnsupportedOperationException(av.toString());
|
|
}
|
|
};
|
|
|
|
/** Translates an {@link AnnotationValue} to a proto representation. */
|
|
private static AnnotationValueProto annotationValueProto(AnnotationValue annotationValue) {
|
|
return annotationValue
|
|
.accept(ANNOTATION_VALUE_TO_PROTO, AnnotationValueProto.newBuilder())
|
|
.build();
|
|
}
|
|
|
|
private class AnnotationValueFromProto implements AnnotationValue {
|
|
private final AnnotationValueProto proto;
|
|
|
|
AnnotationValueFromProto(AnnotationValueProto proto) {
|
|
this.proto = proto;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
switch (proto.getKind()) {
|
|
case BOOLEAN:
|
|
return proto.getBooleanValue();
|
|
case BYTE:
|
|
return (byte) proto.getIntValue();
|
|
case SHORT:
|
|
return (short) proto.getIntValue();
|
|
case CHAR:
|
|
return getCharValue();
|
|
case INT:
|
|
return proto.getIntValue();
|
|
case FLOAT:
|
|
return proto.getFloatValue();
|
|
case LONG:
|
|
return proto.getLongValue();
|
|
case DOUBLE:
|
|
return proto.getDoubleValue();
|
|
case STRING:
|
|
return proto.getStringValue();
|
|
case CLASS_LITERAL:
|
|
return typeProtoConverter.fromProto(proto.getClassLiteral());
|
|
case ENUM:
|
|
return getEnumConstant();
|
|
case ANNOTATION:
|
|
return fromProto(proto.getNestedAnnotation());
|
|
case ARRAY:
|
|
return getArrayValues();
|
|
case UNKNOWN:
|
|
case UNRECOGNIZED:
|
|
// fall through
|
|
}
|
|
throw new AssertionError(proto);
|
|
}
|
|
|
|
@Override
|
|
public <R, P> R accept(AnnotationValueVisitor<R, P> visitor, P passedValue) {
|
|
switch (proto.getKind()) {
|
|
case BOOLEAN:
|
|
return visitor.visitBoolean(proto.getBooleanValue(), passedValue);
|
|
case BYTE:
|
|
return visitor.visitByte((byte) proto.getIntValue(), passedValue);
|
|
case SHORT:
|
|
return visitor.visitShort((short) proto.getIntValue(), passedValue);
|
|
case CHAR:
|
|
return visitor.visitChar(getCharValue(), passedValue);
|
|
case INT:
|
|
return visitor.visitInt(proto.getIntValue(), passedValue);
|
|
case FLOAT:
|
|
return visitor.visitFloat(proto.getFloatValue(), passedValue);
|
|
case LONG:
|
|
return visitor.visitLong(proto.getLongValue(), passedValue);
|
|
case DOUBLE:
|
|
return visitor.visitDouble(proto.getDoubleValue(), passedValue);
|
|
case STRING:
|
|
return visitor.visitString((String) getValue(), passedValue);
|
|
case CLASS_LITERAL:
|
|
return visitor.visitType((TypeMirror) getValue(), passedValue);
|
|
case ENUM:
|
|
return visitor.visitEnumConstant((VariableElement) getValue(), passedValue);
|
|
case ANNOTATION:
|
|
return visitor.visitAnnotation((AnnotationMirror) getValue(), passedValue);
|
|
case ARRAY:
|
|
return visitor.visitArray(getArrayValues(), passedValue);
|
|
case UNKNOWN:
|
|
case UNRECOGNIZED:
|
|
// fall through
|
|
}
|
|
throw new AssertionError(proto);
|
|
}
|
|
|
|
private char getCharValue() {
|
|
checkState(proto.getKind().equals(AnnotationValueProto.Kind.CHAR));
|
|
return proto.getStringValue().charAt(0);
|
|
}
|
|
|
|
private VariableElement getEnumConstant() {
|
|
checkState(proto.getKind().equals(AnnotationValueProto.Kind.ENUM));
|
|
TypeMirror enumType = typeProtoConverter.fromProto(proto.getEnumType());
|
|
return fieldsIn(MoreTypes.asTypeElement(enumType).getEnclosedElements()).stream()
|
|
.filter(value -> value.getSimpleName().contentEquals(proto.getEnumName()))
|
|
.findFirst()
|
|
.get();
|
|
}
|
|
|
|
private ImmutableList<AnnotationValue> getArrayValues() {
|
|
checkState(proto.getKind().equals(AnnotationValueProto.Kind.ARRAY));
|
|
return proto.getArrayValuesList().stream()
|
|
.map(AnnotationValueFromProto::new)
|
|
.collect(toImmutableList());
|
|
}
|
|
}
|
|
}
|