cn.wjybxx.dsonapt.CodecProcessor Maven / Gradle / Ivy
/*
* Copyright 2023-2024 wjybxx([email protected])
*
* 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 cn.wjybxx.dsonapt;
import cn.wjybxx.apt.AptUtils;
import cn.wjybxx.apt.BeanUtils;
import cn.wjybxx.apt.MyAbstractProcessor;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.*;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import java.util.*;
/**
* @author wjybxx
* date 2023/4/13
*/
@AutoService(Processor.class)
public class CodecProcessor extends MyAbstractProcessor {
// region 常量
public static final String CNAME_WireType = "cn.wjybxx.dson.WireType";
public static final String CNAME_NumberStyle = "cn.wjybxx.dson.text.NumberStyle";
public static final String CNAME_StringStyle = "cn.wjybxx.dson.text.StringStyle";
public static final String CNAME_ObjectStyle = "cn.wjybxx.dson.text.ObjectStyle";
public static final String CNAME_TypeInfo = "cn.wjybxx.dsoncodec.TypeInfo";
public static final String CNAME_Options = "cn.wjybxx.dsoncodec.ConverterOptions";
// Dson
private static final String CNAME_SERIALIZABLE = "cn.wjybxx.dsoncodec.annotations.DsonSerializable";
public static final String CNAME_PROPERTY = "cn.wjybxx.dsoncodec.annotations.DsonProperty";
private static final String CNAME_DSON_IGNORE = "cn.wjybxx.dsoncodec.annotations.DsonIgnore";
private static final String CNAME_DSON_READER = "cn.wjybxx.dsoncodec.DsonObjectReader";
private static final String CNAME_DSON_WRITER = "cn.wjybxx.dsoncodec.DsonObjectWriter";
private static final String CNAME_DSON_SCAN_IGNORE = "cn.wjybxx.dsoncodec.annotations.DsonCodecScanIgnore";
// Linker
private static final String CNAME_CODEC_LINKER_GROUP = "cn.wjybxx.dsoncodec.annotations.DsonCodecLinkerGroup";
private static final String CNAME_CODEC_LINKER = "cn.wjybxx.dsoncodec.annotations.DsonCodecLinker";
private static final String CNAME_CODEC_LINKER_BEAN = "cn.wjybxx.dsoncodec.annotations.DsonCodecLinkerBean";
private static final String MNAME_OUTPUT = "outputPackage";
private static final String MNAME_CLASS_PROPS = "props";
// Codec
public static final String CNAME_CODEC = "cn.wjybxx.dsoncodec.DsonCodec";
public static final String MNAME_READ_OBJECT = "readObject";
public static final String MNAME_WRITE_OBJECT = "writeObject";
// AbstractCodec
private static final String CNAME_ABSTRACT_CODEC = "cn.wjybxx.dsoncodec.AbstractDsonCodec";
public static final String MNAME_GET_ENCODER_CLASS = "getEncoderClass";
public static final String MNAME_BEFORE_ENCODE = "beforeEncode";
public static final String MNAME_WRITE_FIELDS = "writeFields";
public static final String MNAME_NEW_INSTANCE = "newInstance";
public static final String MNAME_READ_FIELDS = "readFields";
public static final String MNAME_AFTER_DECODE = "afterDecode";
// EnumCode
private static final String CNAME_ENUM_CODEC = "cn.wjybxx.dsoncodec.codecs.EnumCodec";
public static final String CNAME_ENUM_LITE = "cn.wjybxx.base.EnumLite";
public static final String MNAME_FOR_NUMBER = "forNumber";
public static final String MNAME_GET_NUMBER = "getNumber";
//endregion
// region 字段
public ClassName typeNameTypeInfo;
public ClassName typeNameWireType;
public ClassName typeNameNumberStyle;
public ClassName typeNameStringStyle;
public ClassName typeNameObjectStyle;
public TypeMirror optionsTypeMirror;
// Dson
public TypeElement anno_dsonSerializable;
public TypeMirror anno_dsonProperty;
public TypeMirror anno_dsonIgnore;
public TypeMirror dsonReaderTypeMirror;
public TypeMirror dsonWriterTypeMirror;
public AnnotationSpec dsonScanIgnoreAnnoSpec;
// linker
public TypeElement anno_codecLinkerGroup;
public TypeElement anno_codecLinker;
public TypeElement anno_codecLinkerBean;
// abstractCodec
public TypeElement abstractCodecTypeElement;
public ExecutableElement getEncoderClassMethod;
public ExecutableElement newInstanceMethod;
public ExecutableElement readFieldsMethod;
public ExecutableElement afterDecodeMethod;
public ExecutableElement writeObjectMethod;
public ExecutableElement beforeEncodeMethod;
public ExecutableElement writeFieldsMethod;
// enumCodec
public TypeElement enumCodecTypeElement;
// 特殊类型依赖
// 基础类型
public TypeMirror stringTypeMirror;
public TypeMirror enumLiteTypeMirror;
public TypeMirror objectTypeMirror;
// 集合类型
public TypeMirror mapTypeMirror;
public TypeMirror collectionTypeMirror;
public TypeMirror setTypeMirror;
public TypeMirror enumSetRawTypeMirror;
public TypeMirror enumMapRawTypeMirror;
public TypeMirror linkedHashMapTypeMirror;
public TypeMirror linkedHashSetTypeMirror;
public TypeMirror arrayListTypeMirror;
// endregion
public CodecProcessor() {
}
@Override
public Set getSupportedAnnotationTypes() {
return Set.of(CNAME_SERIALIZABLE, CNAME_CODEC_LINKER_GROUP, CNAME_CODEC_LINKER_BEAN);
}
@Override
protected void ensureInited() {
if (typeNameWireType != null) return;
// common
optionsTypeMirror = elementUtils.getTypeElement(CNAME_Options).asType();
typeNameTypeInfo = ClassName.get(elementUtils.getTypeElement(CNAME_TypeInfo));
typeNameWireType = AptUtils.classNameOfCanonicalName(CNAME_WireType);
typeNameNumberStyle = AptUtils.classNameOfCanonicalName(CNAME_NumberStyle);
typeNameStringStyle = AptUtils.classNameOfCanonicalName(CNAME_StringStyle);
typeNameObjectStyle = AptUtils.classNameOfCanonicalName(CNAME_ObjectStyle);
// dson
anno_dsonSerializable = elementUtils.getTypeElement(CNAME_SERIALIZABLE);
anno_dsonProperty = elementUtils.getTypeElement(CNAME_PROPERTY).asType();
anno_dsonIgnore = elementUtils.getTypeElement(CNAME_DSON_IGNORE).asType();
dsonReaderTypeMirror = elementUtils.getTypeElement(CNAME_DSON_READER).asType();
dsonWriterTypeMirror = elementUtils.getTypeElement(CNAME_DSON_WRITER).asType();
dsonScanIgnoreAnnoSpec = AnnotationSpec.builder(ClassName.get(elementUtils.getTypeElement(CNAME_DSON_SCAN_IGNORE)))
.build();
// linker
anno_codecLinkerGroup = elementUtils.getTypeElement(CNAME_CODEC_LINKER_GROUP);
anno_codecLinker = elementUtils.getTypeElement(CNAME_CODEC_LINKER);
anno_codecLinkerBean = elementUtils.getTypeElement(CNAME_CODEC_LINKER_BEAN);
// Codec
TypeElement codecTypeElement = elementUtils.getTypeElement(CNAME_CODEC);
getEncoderClassMethod = AptUtils.findMethodByName(codecTypeElement, MNAME_GET_ENCODER_CLASS);
// abstractCodec
abstractCodecTypeElement = elementUtils.getTypeElement(CNAME_ABSTRACT_CODEC);
{
List allMethodsWithInherit = BeanUtils.getAllMethodsWithInherit(abstractCodecTypeElement);
// dson
newInstanceMethod = findCodecMethod(allMethodsWithInherit, MNAME_NEW_INSTANCE, dsonReaderTypeMirror);
readFieldsMethod = findCodecMethod(allMethodsWithInherit, MNAME_READ_FIELDS, dsonReaderTypeMirror);
afterDecodeMethod = findCodecMethod(allMethodsWithInherit, MNAME_AFTER_DECODE, dsonReaderTypeMirror);
writeObjectMethod = findCodecMethod(allMethodsWithInherit, MNAME_WRITE_OBJECT, dsonWriterTypeMirror);
beforeEncodeMethod = findCodecMethod(allMethodsWithInherit, MNAME_BEFORE_ENCODE, dsonWriterTypeMirror);
writeFieldsMethod = findCodecMethod(allMethodsWithInherit, MNAME_WRITE_FIELDS, dsonWriterTypeMirror);
}
// enumLiteCodec
enumCodecTypeElement = elementUtils.getTypeElement(CNAME_ENUM_CODEC);
// 特殊类型依赖
// 基础类型
stringTypeMirror = elementUtils.getTypeElement(String.class.getCanonicalName()).asType();
enumLiteTypeMirror = elementUtils.getTypeElement(CNAME_ENUM_LITE).asType();
objectTypeMirror = elementUtils.getTypeElement(Object.class.getCanonicalName()).asType();
// 集合
mapTypeMirror = elementUtils.getTypeElement(Map.class.getCanonicalName()).asType();
collectionTypeMirror = elementUtils.getTypeElement(Collection.class.getCanonicalName()).asType();
setTypeMirror = elementUtils.getTypeElement(Set.class.getCanonicalName()).asType();
enumSetRawTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, EnumSet.class));
enumMapRawTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, EnumMap.class));
linkedHashMapTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, LinkedHashMap.class));
linkedHashSetTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, LinkedHashSet.class));
arrayListTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, ArrayList.class));
}
private ExecutableElement findCodecMethod(List allMethodsWithInherit,
String methodName, TypeMirror firstArg) {
return allMethodsWithInherit.stream()
.filter(e -> e.getKind() == ElementKind.METHOD && e.getSimpleName().toString().equals(methodName))
.filter(e -> e.getParameters().size() > 0
&& AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, e.getParameters().get(0).asType(), firstArg)
)
.findFirst()
.orElseThrow(() -> new RuntimeException("method is absent, methodName: " + methodName));
}
@Override
protected boolean doProcess(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
final Set allTypeElements = AptUtils.selectSourceFileAny(roundEnv, elementUtils,
anno_dsonSerializable, anno_codecLinkerGroup, anno_codecLinkerBean);
for (TypeElement typeElement : allTypeElements) {
try {
// 各种缓存,避免频繁解析类型信息
Context context = new Context(typeElement);
context.dsonSerialAnnoMirror = AptUtils.findAnnotation(typeUtils, typeElement, anno_dsonSerializable.asType())
.orElse(null);
context.linkerGroupAnnoMirror = AptUtils.findAnnotation(typeUtils, typeElement, anno_codecLinkerGroup.asType())
.orElse(null);
context.linkerBeanAnnoMirror = AptUtils.findAnnotation(typeUtils, typeElement, anno_codecLinkerBean.asType())
.orElse(null);
context.aptClassProps = AptClassProps.parse(typeUtils, typeElement, anno_dsonSerializable.asType());
cacheFields(context);
// 判断是哪类注解
if (context.linkerGroupAnnoMirror != null) {
// 不是为自己生成,而是为字段生成
processLinkerGroup(context);
} else if (context.linkerBeanAnnoMirror != null) {
// 不是为自己生成,当前类是Codec配置类
processLinkerBean(context);
} else {
processDirectType(context);
}
} catch (Throwable e) {
messager.printMessage(Diagnostic.Kind.ERROR, AptUtils.getStackTrace(e), typeElement);
}
}
return true;
}
private void processLinkerBean(Context linkerBeanContext) {
final AnnotationMirror linkerBeanAnnoMirror = linkerBeanContext.linkerBeanAnnoMirror;
final String outPackage = getOutputPackage(linkerBeanContext.typeElement, linkerBeanAnnoMirror);
DeclaredType declaredType; // 被投影的类型
{
AnnotationValue annotationValue = AptUtils.getAnnotationValue(linkerBeanAnnoMirror, "value");
Objects.requireNonNull(annotationValue, "classProps");
declaredType = AptUtils.findDeclaredType(AptUtils.getAnnotationValueTypeMirror(annotationValue));
Objects.requireNonNull(declaredType);
}
AnnotationValue classPropsAnnoValue = AptUtils.getAnnotationValue(linkerBeanAnnoMirror, MNAME_CLASS_PROPS);
AptClassProps aptClassProps = classPropsAnnoValue == null ?
new AptClassProps() : AptClassProps.parse(typeUtils, (AnnotationMirror) classPropsAnnoValue.getValue());
// 创建模拟数据
TypeElement typeElement = (TypeElement) declaredType.asElement();
Context context = new Context(typeElement);
context.linkerBeanAddAnnotations = getAdditionalAnnotations(aptClassProps);
// 模拟为dson数据
context.dsonSerialAnnoMirror = linkerBeanAnnoMirror;
context.dsonAddAnnotations = context.linkerBeanAddAnnotations;
context.outPackage = outPackage;
context.aptClassProps = aptClassProps;
cacheFields(context);
// 修正ClassProps注解
{
TypeMirror linkerBeanTypeMirror = linkerBeanContext.typeElement.asType();
aptClassProps.codecProxyTypeElement = linkerBeanContext.typeElement;
aptClassProps.codecProxyClassName = TypeName.get(typeUtils.erasure(linkerBeanTypeMirror));
aptClassProps.codecProxyEnclosedElements = linkerBeanContext.typeElement.getEnclosedElements();
}
// 修正字段的FieldProps注解 —— 将LinkerBean上的注解信息转移到目标类
{
cacheFieldProps(linkerBeanContext);
context.fieldPropsMap.clear();
// 按name缓存,提高效率
Map fieldName2FieldPropsMap = HashMap.newHashMap(linkerBeanContext.fieldPropsMap.size());
linkerBeanContext.fieldPropsMap.forEach((k, v) -> {
fieldName2FieldPropsMap.put(k.getSimpleName().toString(), v);
});
for (VariableElement field : context.allFields) {
AptFieldProps aptFieldProps = fieldName2FieldPropsMap.get(field.getSimpleName().toString());
if (aptFieldProps == null) aptFieldProps = new AptFieldProps();
context.fieldPropsMap.put(field, aptFieldProps);
}
}
// dson
{
context.serialTypeElement = anno_dsonSerializable;
context.ignoreTypeMirror = anno_dsonIgnore;
context.readerTypeMirror = dsonReaderTypeMirror;
context.writerTypeMirror = dsonWriterTypeMirror;
context.serialFields = new ArrayList<>();
checkTypeElement(context);
context.dsonSerialFields.addAll(context.serialFields);
}
generateCodec(context);
}
private void processLinkerGroup(Context groupContext) {
final String outPackage = getOutputPackage(groupContext.typeElement, groupContext.linkerGroupAnnoMirror);
for (VariableElement variableElement : groupContext.allFields) {
AnnotationMirror linkerAnnoMirror = AptUtils.findAnnotation(typeUtils, variableElement, anno_codecLinker.asType())
.orElse(null);
if (linkerAnnoMirror == null) { // 不需要链接的字段
continue;
}
DeclaredType declaredType = AptUtils.findDeclaredType(variableElement.asType());
if (declaredType == null) {
messager.printMessage(Diagnostic.Kind.ERROR, "Bad Linker Target", variableElement);
continue;
}
AnnotationValue classPropsAnnoValue = AptUtils.getAnnotationValue(linkerAnnoMirror, MNAME_CLASS_PROPS);
AptClassProps aptClassProps = classPropsAnnoValue == null ?
new AptClassProps() : AptClassProps.parse(typeUtils, (AnnotationMirror) classPropsAnnoValue.getValue());
// 创建模拟数据
TypeElement typeElement = (TypeElement) declaredType.asElement();
Context context = new Context(typeElement);
context.linkerAddAnnotations = getAdditionalAnnotations(aptClassProps);
// 模拟为dson数据
context.dsonSerialAnnoMirror = linkerAnnoMirror;
context.dsonAddAnnotations = context.linkerAddAnnotations;
context.outPackage = outPackage;
context.aptClassProps = aptClassProps;
cacheFields(context);
cacheFieldProps(context);
// dson
{
context.serialTypeElement = anno_dsonSerializable;
context.ignoreTypeMirror = anno_dsonIgnore;
context.readerTypeMirror = dsonReaderTypeMirror;
context.writerTypeMirror = dsonWriterTypeMirror;
context.serialFields = new ArrayList<>();
checkTypeElement(context);
context.dsonSerialFields.addAll(context.serialFields);
}
generateCodec(context);
}
}
private void processDirectType(Context context) {
cacheFieldProps(context);
// dson
if (context.dsonSerialAnnoMirror != null) {
context.dsonAddAnnotations = getAdditionalAnnotations(context.aptClassProps);
context.serialTypeElement = anno_dsonSerializable;
context.ignoreTypeMirror = anno_dsonIgnore;
context.readerTypeMirror = dsonReaderTypeMirror;
context.writerTypeMirror = dsonWriterTypeMirror;
context.serialFields = new ArrayList<>();
checkTypeElement(context);
context.dsonSerialFields.addAll(context.serialFields);
}
generateCodec(context);
}
private void generateCodec(Context context) {
TypeElement typeElement = context.typeElement;
if (isEnumLite(typeElement.asType())) {
DeclaredType superDeclaredType = typeUtils.getDeclaredType(enumCodecTypeElement, typeUtils.erasure(typeElement.asType()));
initTypeBuilder(context, typeElement, superDeclaredType);
//
new EnumCodecGenerator(this, typeElement, context).execute();
} else {
DeclaredType superDeclaredType = typeUtils.getDeclaredType(abstractCodecTypeElement, typeUtils.erasure(typeElement.asType()));
initTypeBuilder(context, typeElement, superDeclaredType);
// 先生成常量字段
SchemaGenerator schemaGenerator = new SchemaGenerator(this, context);
schemaGenerator.execute();
// 不论注解是否存在,所有方法都要实现
// dson
{
context.serialAnnoMirror = context.dsonSerialAnnoMirror;
context.scanIgnoreAnnoSpec = dsonScanIgnoreAnnoSpec;
context.additionalAnnotations = context.dsonAddAnnotations;
context.serialTypeElement = anno_dsonSerializable;
context.ignoreTypeMirror = anno_dsonIgnore;
context.readerTypeMirror = dsonReaderTypeMirror;
context.writerTypeMirror = dsonWriterTypeMirror;
context.serialFields = context.dsonSerialFields;
context.serialNameAccess = "names_";
new PojoCodecGenerator(this, context).execute();
}
}
// 写入文件
if (context.outPackage != null) {
AptUtils.writeToFile(typeElement, context.typeBuilder, context.outPackage, messager, filer);
} else {
AptUtils.writeToFile(typeElement, context.typeBuilder, elementUtils, messager, filer);
}
}
// region
private void cacheFields(Context context) {
context.allFieldsAndMethodWithInherit = BeanUtils.getAllFieldsAndMethodsWithInherit(context.typeElement);
context.allFields = context.allFieldsAndMethodWithInherit.stream()
.filter(e -> e.getKind() == ElementKind.FIELD && !e.getModifiers().contains(Modifier.STATIC))
.map(e -> (VariableElement) e)
.toList();
}
private void cacheFieldProps(Context context) {
context.allFields.forEach(variableElement -> {
AptFieldProps aptFieldProps = AptFieldProps.parse(typeUtils, variableElement, anno_dsonProperty);
// dsonIgnore
AptUtils.findAnnotation(typeUtils, variableElement, anno_dsonIgnore)
.ifPresent(ignoreAnnoMirror -> aptFieldProps.dsonIgnore = AptUtils.getAnnotationValueValue(ignoreAnnoMirror, "value"));
context.fieldPropsMap.put(variableElement, aptFieldProps);
});
}
/** 获取输出目录 -- 默认为配置类的路径 */
private String getOutputPackage(TypeElement typeElement, AnnotationMirror annotationMirror) {
String outPackage = AptUtils.getAnnotationValueValue(annotationMirror, MNAME_OUTPUT);
if (AptUtils.isBlank(outPackage)) {
return elementUtils.getPackageOf(typeElement).getQualifiedName().toString();
}
return outPackage;
}
/** 获取为生成的Codec附加的注解 */
private List getAdditionalAnnotations(AptClassProps aptClassProps) {
if (aptClassProps.additionalAnnotations.isEmpty()) {
return List.of();
}
List result = new ArrayList<>(aptClassProps.additionalAnnotations.size());
for (TypeMirror typeMirror : aptClassProps.additionalAnnotations) {
final ClassName className = (ClassName) ClassName.get(typeMirror);
result.add(AnnotationSpec.builder(className)
.build());
}
return result;
}
private void initTypeBuilder(Context context, TypeElement typeElement, DeclaredType superDeclaredType) {
context.superDeclaredType = superDeclaredType;
context.typeBuilder = TypeSpec.classBuilder(getCodecName(typeElement))
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addAnnotation(AptUtils.SUPPRESS_UNCHECKED_RAWTYPES)
.addAnnotation(processorInfoAnnotation)
.superclass(TypeName.get(superDeclaredType));
}
private String getCodecName(TypeElement typeElement) {
return AptUtils.getProxyClassName(elementUtils, typeElement, "Codec");
}
// endregion
private void checkTypeElement(Context context) {
TypeElement typeElement = context.typeElement;
if (!isClassOrEnum(typeElement)) {
messager.printMessage(Diagnostic.Kind.ERROR, "unsupported type", typeElement);
return;
}
if (typeElement.getKind() == ElementKind.ENUM) {
checkEnum(typeElement);
} else {
checkNormalClass(context);
}
}
// region 枚举检查
/**
* 检查枚举 - 要自动序列化的枚举,必须实现EnumLite接口且提供forNumber方法。
*/
private void checkEnum(TypeElement typeElement) {
if (!isEnumLite(typeElement.asType())) {
messager.printMessage(Diagnostic.Kind.ERROR,
"serializable enum must implement EnumLite",
typeElement);
return;
}
if (!containNotPrivateStaticForNumberMethod(typeElement)) {
messager.printMessage(Diagnostic.Kind.ERROR,
"serializable enum must contains a not private 'static T forNumber(int)' method!",
typeElement);
}
}
/**
* 是否包含静态的非private的forNumber方法
*/
private boolean containNotPrivateStaticForNumberMethod(TypeElement typeElement) {
return typeElement.getEnclosedElements().stream()
.filter(e -> e.getKind() == ElementKind.METHOD)
.map(e -> (ExecutableElement) e)
.anyMatch(e -> e.getModifiers().contains(Modifier.PUBLIC)
&& e.getModifiers().contains(Modifier.STATIC)
&& e.getParameters().size() == 1
&& e.getSimpleName().toString().equals(MNAME_FOR_NUMBER)
&& e.getParameters().get(0).asType().getKind() == TypeKind.INT);
}
// endregion
// region 普通类检查
private void checkNormalClass(Context context) {
final AptClassProps aptClassProps = context.aptClassProps;
if (aptClassProps.isSingleton()) {
return;
}
TypeElement typeElement = context.typeElement;
checkConstructor(typeElement, context.readerTypeMirror);
final List extends Element> allFieldsAndMethodWithInherit = context.allFieldsAndMethodWithInherit;
final List extends Element> instMethodList = context.allFieldsAndMethodWithInherit.stream()
.filter(e -> e.getKind() == ElementKind.METHOD && !e.getModifiers().contains(Modifier.STATIC))
.toList();
for (Element element : allFieldsAndMethodWithInherit) {
if (element.getKind() != ElementKind.FIELD) {
continue;
}
final VariableElement variableElement = (VariableElement) element;
final AptFieldProps aptFieldProps = context.fieldPropsMap.get(variableElement);
if (!isSerializableField(variableElement, instMethodList, aptFieldProps)) {
continue;
}
context.serialFields.add(variableElement);
if (isAutoWriteField(variableElement, aptClassProps, aptFieldProps)) {
if (aptFieldProps.hasWriteProxy()) {
continue;
}
// 工具写:需要提供可直接取值或包含非private的getter方法
if (AptUtils.isBlank(aptFieldProps.getter)
&& !canGetDirectly(variableElement, typeElement)
&& findNotPrivateGetter(variableElement, allFieldsAndMethodWithInherit) == null) {
messager.printMessage(Diagnostic.Kind.ERROR,
String.format("serializable field (%s) must contains a not private getter or canGetDirectly", variableElement.getSimpleName()),
typeElement); // 可能无法定位到超类字段,因此打印到Type
continue;
}
}
if (isAutoReadField(variableElement, aptClassProps, aptFieldProps)) {
if (aptFieldProps.hasReadProxy()) {
continue;
}
// 工具读:需要提供可直接赋值或非private的setter方法
if (AptUtils.isBlank(aptFieldProps.setter)
&& !canSetDirectly(variableElement, typeElement)
&& findNotPrivateSetter(variableElement, allFieldsAndMethodWithInherit) == null) {
messager.printMessage(Diagnostic.Kind.ERROR,
String.format("serializable field (%s) must contains a not private setter or canSetDirectly", variableElement.getSimpleName()),
typeElement); // 可能无法定位到超类字段,因此打印到Type
continue;
}
}
}
}
/** 检查是否包含无参构造方法或解析构造方法 */
private void checkConstructor(TypeElement typeElement, TypeMirror readerTypeMirror) {
if (typeElement.getModifiers().contains(Modifier.ABSTRACT)) {
return;
}
if (BeanUtils.containsNoArgsConstructor(typeElement)
|| containsReaderConstructor(typeElement, readerTypeMirror)
|| containsNewInstanceMethod(typeElement, readerTypeMirror)) {
return;
}
messager.printMessage(Diagnostic.Kind.ERROR,
"SerializableClass %s must contains no-args constructor or reader-args constructor!",
typeElement);
}
// region 钩子方法检查
/** 是否包含 T(Reader reader) 构造方法 */
public boolean containsReaderConstructor(TypeElement typeElement, TypeMirror readerTypeMirror) {
return BeanUtils.containsOneArgsConstructor(typeUtils, typeElement, readerTypeMirror);
}
/** 是否包含 newInstance 静态解码方法 -- 只能从当前类型查询 */
public boolean containsNewInstanceMethod(TypeElement typeElement, TypeMirror readerTypeMirror) {
return containsHookMethod(typeElement.getEnclosedElements(), MNAME_NEW_INSTANCE, readerTypeMirror);
}
/** 是否包含 readerObject 实例方法 */
public boolean containsReadObjectMethod(List extends Element> allFieldsAndMethodWithInherit, TypeMirror readerTypeMirror) {
return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_READ_OBJECT, readerTypeMirror);
}
/** 是否包含 writeObject 实例方法 */
public boolean containsWriteObjectMethod(List extends Element> allFieldsAndMethodWithInherit, TypeMirror writerTypeMirror) {
return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_WRITE_OBJECT, writerTypeMirror);
}
/** 是否包含 beforeEncode 实例方法 */
public boolean containsBeforeEncodeMethod(List extends Element> allFieldsAndMethodWithInherit) {
return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_BEFORE_ENCODE, optionsTypeMirror);
}
/** 是否包含 afterDecode 实例方法 */
public boolean containsAfterDecodeMethod(List extends Element> allFieldsAndMethodWithInherit) {
return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_AFTER_DECODE, optionsTypeMirror);
}
private boolean containsHookMethod(List extends Element> allFieldsAndMethodWithInherit, String methodName, TypeMirror argTypeMirror) {
return allFieldsAndMethodWithInherit.stream()
.filter(e -> e.getKind() == ElementKind.METHOD)
.map(e -> (ExecutableElement) e)
.anyMatch(e -> e.getModifiers().contains(Modifier.PUBLIC)
&& e.getParameters().size() == 1
&& e.getSimpleName().toString().equals(methodName)
&& AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, e.getParameters().get(0).asType(), argTypeMirror));
}
// endregion
// region 字段检查
/**
* 测试{@link TypeElement}是否可以直接读取字段。
* (这里需要考虑继承问题)
*
* @param variableElement 类字段,可能是继承的字段
* @return 如果可直接取值,则返回true
*/
public boolean canGetDirectly(final VariableElement variableElement, TypeElement typeElement) {
return variableElement.getModifiers().contains(Modifier.PUBLIC);
}
/**
* 测试{@link TypeElement}是否可以直接写字段。
* (这里需要考虑继承问题)
*
* @param variableElement 类字段,可能是继承的字段
* @return 如果可直接赋值,则返回true
*/
public boolean canSetDirectly(final VariableElement variableElement, TypeElement typeElement) {
if (variableElement.getModifiers().contains(Modifier.FINAL)) {
return false;
}
return variableElement.getModifiers().contains(Modifier.PUBLIC);
}
/** 字段是否是类的成员或同包类的成员 -- 兼容性不好,生成的Codec可能在其它包 */
@Deprecated
private boolean isMemberOrPackageMember(VariableElement variableElement, TypeElement typeElement) {
final TypeElement enclosingElement = (TypeElement) variableElement.getEnclosingElement();
if (enclosingElement.equals(typeElement)) {
return true;
}
return elementUtils.getPackageOf(enclosingElement).equals(elementUtils.getPackageOf(typeElement));
}
/**
* 查找非private的getter方法
*
* @param allMethodWithInherit 所有的字段和方法,可能在父类中
*/
public ExecutableElement findNotPrivateGetter(final VariableElement variableElement, final List extends Element> allMethodWithInherit) {
return BeanUtils.findNotPrivateGetter(typeUtils, variableElement, allMethodWithInherit);
}
/**
* 查找非private的setter方法
*
* @param allMethodWithInherit 所有的字段和方法,可能在父类中
*/
public ExecutableElement findNotPrivateSetter(final VariableElement variableElement, final List extends Element> allMethodWithInherit) {
return BeanUtils.findNotPrivateSetter(typeUtils, variableElement, allMethodWithInherit);
}
/** 是否是可序列化的字段 */
private boolean isSerializableField(VariableElement variableElement, List extends Element> instMethodList, AptFieldProps aptFieldProps) {
if (variableElement.getModifiers().contains(Modifier.STATIC)) {
return false;
}
// 有注解的情况下,取决于注解的值
Boolean ignore = aptFieldProps.dsonIgnore;
if (ignore != null) return ignore;
// 无注解的情况下,默认忽略 transient 字段
if (variableElement.getModifiers().contains(Modifier.TRANSIENT)) {
return false;
}
// 判断public和getter
if (variableElement.getModifiers().contains(Modifier.PUBLIC)) {
return true;
}
return BeanUtils.containsNotPrivateGetter(typeUtils, variableElement, instMethodList);
}
/** 是否是托管写的字段 */
boolean isAutoWriteField(VariableElement variableElement, AptClassProps aptClassProps, AptFieldProps aptFieldProps) {
if (aptClassProps.isSingleton()) {
return false;
}
// 优先判断skip属性
if (isSkipFields(variableElement, aptClassProps)) {
return false;
}
return true;
}
/** 是否是托管写的字段 */
boolean isAutoReadField(VariableElement variableElement, AptClassProps aptClassProps, AptFieldProps aptFieldProps) {
if (aptClassProps.isSingleton()) {
return false;
}
// final必定或构造方法读
if (variableElement.getModifiers().contains(Modifier.FINAL)) {
return false;
}
// 优先判断skip属性
if (isSkipFields(variableElement, aptClassProps)) {
return false;
}
return true;
}
private boolean isSkipFields(VariableElement variableElement, AptClassProps aptClassProps) {
if (aptClassProps.skipFields.isEmpty()) {
return false;
}
String fieldName = variableElement.getSimpleName().toString();
if (aptClassProps.skipFields.contains(fieldName)) {
return true;
}
if (!aptClassProps.clippedSkipFields.contains(fieldName)) {
return false;
}
// 测试SimpleClassName和FullClassName
TypeElement declaredTypeElement = (TypeElement) variableElement.getEnclosingElement();
String simpleClassName = declaredTypeElement.getSimpleName().toString();
if (aptClassProps.skipFields.contains(simpleClassName + "." + fieldName)) {
return true;
}
String fullClassName = declaredTypeElement.getQualifiedName().toString();
if (aptClassProps.skipFields.contains(fullClassName + "." + fieldName)) {
return true;
}
return false;
}
// endregion
// endregion
// region 类型测试
protected boolean isClassOrEnum(TypeElement typeElement) {
return typeElement.getKind() == ElementKind.CLASS
|| typeElement.getKind() == ElementKind.ENUM;
}
protected boolean isString(TypeMirror typeMirror) {
return typeUtils.isSameType(typeMirror, stringTypeMirror);
}
protected boolean isByteArray(TypeMirror typeMirror) {
return AptUtils.isByteArray(typeMirror);
}
protected boolean isEnumLite(TypeMirror typeMirror) {
return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, enumLiteTypeMirror);
}
protected boolean isMap(TypeMirror typeMirror) {
return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, mapTypeMirror);
}
protected boolean isCollection(TypeMirror typeMirror) {
return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, collectionTypeMirror);
}
protected boolean isSet(TypeMirror typeMirror) {
return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, setTypeMirror);
}
protected boolean isEnumSet(TypeMirror typeMirror) {
return typeMirror == enumSetRawTypeMirror || AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, typeMirror, enumSetRawTypeMirror);
}
protected boolean isEnumMap(TypeMirror typeMirror) {
return typeMirror == enumMapRawTypeMirror || AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, typeMirror, enumMapRawTypeMirror);
}
// endregion
// region overriding util
public MethodSpec newGetEncoderClassMethod(DeclaredType superDeclaredType, TypeName rawTypeName) {
return MethodSpec.overriding(getEncoderClassMethod, superDeclaredType, typeUtils)
.addStatement("return $T.class", rawTypeName)
.addAnnotation(AptUtils.ANNOTATION_NONNULL)
.build();
}
public MethodSpec.Builder newNewInstanceMethodBuilder(DeclaredType superDeclaredType) {
return MethodSpec.overriding(newInstanceMethod, superDeclaredType, typeUtils);
}
public MethodSpec.Builder newReadFieldsMethodBuilder(DeclaredType superDeclaredType) {
return MethodSpec.overriding(readFieldsMethod, superDeclaredType, typeUtils);
}
public MethodSpec.Builder newAfterDecodeMethodBuilder(DeclaredType superDeclaredType) {
return MethodSpec.overriding(afterDecodeMethod, superDeclaredType, typeUtils);
}
public MethodSpec.Builder newWriteObjectMethodBuilder(DeclaredType superDeclaredType) {
return MethodSpec.overriding(writeObjectMethod, superDeclaredType, typeUtils);
}
public MethodSpec.Builder newBeforeEncodeMethodBuilder(DeclaredType superDeclaredType) {
return MethodSpec.overriding(beforeEncodeMethod, superDeclaredType, typeUtils);
}
public MethodSpec.Builder newWriteFieldsMethodBuilder(DeclaredType superDeclaredType) {
return MethodSpec.overriding(writeFieldsMethod, superDeclaredType, typeUtils);
}
// endregion
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy