/* * Copyright 2019 wjybxx * * 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 iBn 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 com.wjybxx.fastjgame.apt.utils; import com.squareup.javapoet.TypeName; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.lang.model.element.*; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import java.util.List; import java.util.stream.Collectors; /** * JavaBean工具类 * * @author wjybxx * @version 1.0 * date - 2019/12/8 * github - https://github.com/hl845740757 */ public class BeanUtils { public static final String INDEXABLE_OBJECT_CANONICAL_NAME = "com.wjybxx.fastjgame.utils.dsl.IndexableObject"; public static final String FOR_INDEX_METHOD_NAME = "forIndex"; public static final String GET_INDEX_METHOD_NAME = "getIndex"; public static final String INDEXABLE_ENUM_CANONICAL_NAME = "com.wjybxx.fastjgame.utils.dsl.IndexableEnum"; public static final String FOR_NUMBER_METHOD_NAME = "forNumber"; public static final String GET_NUMBER_METHOD_NAME = "getNumber"; /** * 判断一个类是否包含无参构造方法 */ public static boolean containsNoArgsConstructor(TypeElement typeElement) { return getNoArgsConstructor(typeElement) != null; } /** * 查找无参构造方法 */ @Nullable public static ExecutableElement getNoArgsConstructor(TypeElement typeElement) { return typeElement.getEnclosedElements().stream() .filter(e -> e.getKind() == ElementKind.CONSTRUCTOR) .map(e -> (ExecutableElement) e) .filter(e -> e.getParameters().size() == 0) .findFirst() .orElse(null); } /** * 获取类的所有字段和方法,包含继承得到的字段和方法 * {@link Elements#getAllMembers(TypeElement)}只包含父类的公共属性,不包含私有的东西。 */ public static List<Element> getAllFieldsAndMethodsWithInherit(TypeElement typeElement) { final List<TypeElement> flatInherit = AutoUtils.flatInheritAndReverse(typeElement); return flatInherit.stream() .flatMap(e -> e.getEnclosedElements().stream()) .filter(e -> e.getKind() == ElementKind.METHOD || e.getKind() == ElementKind.FIELD) .collect(Collectors.toList()); } /** * 是否包含非private的setter方法 */ public static boolean containsNotPrivateSetterMethod(Types typeUtils, VariableElement variableElement, List<? extends Element> allFieldsAndMethodWithInherit) { final String fieldName = variableElement.getSimpleName().toString(); final String setterMethodName = BeanUtils.setterMethodName(fieldName, isPrimitiveBoolean(variableElement.asType())); return allFieldsAndMethodWithInherit.stream() .filter(e -> e.getKind() == ElementKind.METHOD) .filter(e -> !e.getModifiers().contains(Modifier.PRIVATE)) .map(e -> (ExecutableElement) e) .filter(e -> e.getParameters().size() == 1) .filter(e -> typeUtils.isSameType(variableElement.asType(), e.getParameters().get(0).asType())) .anyMatch(e -> { final String methodName = e.getSimpleName().toString(); return methodName.equals(setterMethodName); }); } /** * 是否包含非private的getter方法 */ public static boolean containsNotPrivateGetterMethod(Types typeUtils, VariableElement variableElement, List<? extends Element> allFieldsAndMethodWithInherit) { final String fieldName = variableElement.getSimpleName().toString(); final String getterMethodName = BeanUtils.getterMethodName(fieldName, isPrimitiveBoolean(variableElement.asType())); return allFieldsAndMethodWithInherit.stream() .filter(e -> e.getKind() == ElementKind.METHOD) .filter(e -> !e.getModifiers().contains(Modifier.PRIVATE)) .map(e -> (ExecutableElement) e) .filter(e -> typeUtils.isSameType(variableElement.asType(), e.getReturnType())) .anyMatch(e -> { final String methodName = e.getSimpleName().toString(); return methodName.equals(getterMethodName); }); } /** * 是否是基本类型的boolean */ public static boolean isPrimitiveBoolean(TypeMirror typeMirror) { return typeMirror.getKind() == TypeKind.BOOLEAN; } /** * 首字符大写 * * @param str content * @return 首字符大写的字符串 */ public static String firstCharToUpperCase(@Nonnull String str) { if (str.length() > 1) { return str.substring(0, 1).toUpperCase() + str.substring(1); } else { return str.toUpperCase(); } } /** * 首字母小写 * * @param str content * @return 首字符小写的字符串 */ public static String firstCharToLowerCase(@Nonnull String str) { if (str.length() > 1) { return str.substring(0, 1).toLowerCase() + str.substring(1); } else { return str.toLowerCase(); } } /** * 获取getter方法的名字 * * @param filedName 字段名字 * @param isPrimitiveBoolean 是否是bool值 - 坑太多了,只有基本类型的boolean才会变成is,包装类型的不会 * @return 方法名 */ public static String getterMethodName(String filedName, boolean isPrimitiveBoolean) { if (isFirstOrSecondCharUpperCase(filedName)) { // 这里参数名一定不是is开头 // 前两个字符任意一个大写,则参数名直接拼在get/is后面 if (isPrimitiveBoolean) { return "is" + filedName; } else { return "get" + filedName; } } // 到这里前两个字符都是小写 if (isPrimitiveBoolean) { // 如果参数名以 is 开头,则直接返回,否则 is + 首字母大写 - is 还要特殊处理 if (filedName.length() > 2 && filedName.startsWith("is")) { return filedName; } else { return "is" + firstCharToUpperCase(filedName); } } else { return "get" + firstCharToUpperCase(filedName); } } /** * 获取setter方法的名字 * * @param filedName 字段名字 * @return 方法名 */ public static String setterMethodName(String filedName, boolean isPrimitiveBoolean) { if (isFirstOrSecondCharUpperCase(filedName)) { // 这里参数名一定不是is开头 // 前两个字符任意一个大写,则参数名直接拼在set后面 return "set" + filedName; } // 到这里前两个字符都是小写 - is 还要特殊处理。 if (isPrimitiveBoolean) { if (filedName.length() > 2 && filedName.startsWith("is")) { return "set" + firstCharToUpperCase(filedName.substring(2)); } else { return "set" + firstCharToUpperCase(filedName); } } else { return "set" + firstCharToUpperCase(filedName); } } /** * 是否是基本类型的boolean * * @param typeName 类型描述名 * @return 如果boolean类型或Boolean则返回true */ public static boolean isPrimitiveBoolean(TypeName typeName) { return typeName == TypeName.BOOLEAN; } /** * 查询名字的第一个或第二个字符是否是大写 */ private static boolean isFirstOrSecondCharUpperCase(String name) { if (name.length() > 0 && Character.isUpperCase(name.charAt(0))) { return true; } if (name.length() > 1 && Character.isUpperCase(name.charAt(1))) { return true; } return false; } }