View Javadoc
1   package top.infra.common;
2   
3   import static com.google.common.base.Charsets.UTF_8;
4   import static com.google.common.base.Preconditions.checkArgument;
5   import static com.google.common.base.Preconditions.checkState;
6   import static com.google.common.collect.Sets.newLinkedHashSetWithExpectedSize;
7   import static java.util.stream.Collectors.toList;
8   import static org.apache.commons.lang3.ArrayUtils.contains;
9   import static org.apache.commons.lang3.StringUtils.isNotBlank;
10  
11  import lombok.SneakyThrows;
12  
13  import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
14  import org.springframework.beans.factory.config.BeanDefinition;
15  import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
16  import org.springframework.core.io.Resource;
17  import org.springframework.core.type.ClassMetadata;
18  import org.springframework.core.type.classreading.MetadataReader;
19  import org.springframework.core.type.classreading.MetadataReaderFactory;
20  import org.springframework.core.type.filter.AbstractClassTestingTypeFilter;
21  import org.springframework.core.type.filter.AssignableTypeFilter;
22  import org.springframework.core.type.filter.TypeFilter;
23  
24  import java.io.File;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.net.URLClassLoader;
28  import java.util.Arrays;
29  import java.util.List;
30  import java.util.Optional;
31  import java.util.Set;
32  import java.util.function.Function;
33  
34  import commonsio.IOUtils;
35  
36  public abstract class ClassUtils {
37  
38      private ClassUtils() {
39      }
40  
41      public static boolean isPresent(final String className) {
42          return isPresent(className, null);
43      }
44  
45      /**
46       * see: {@link org.springframework.boot.autoconfigure.condition.OnClassCondition}
47       *
48       * @param className   className
49       * @param classLoader classLoader
50       * @return isPresent
51       */
52      public static boolean isPresent(final String className, ClassLoader classLoader) {
53          if (classLoader == null) {
54              classLoader = org.springframework.util.ClassUtils.getDefaultClassLoader();
55          }
56          try {
57              forName(className, classLoader);
58              return true;
59          } catch (final Throwable ex) {
60              return false;
61          }
62      }
63  
64      public static Class<?> forName(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
65          if (classLoader != null) {
66              return classLoader.loadClass(className);
67          }
68          return Class.forName(className);
69      }
70  
71      public static Optional<Class<?>> forName(final String className) {
72          try {
73              final ClassLoader classLoader = org.springframework.util.ClassUtils.getDefaultClassLoader();
74              final Class<?> result;
75              if (classLoader != null) {
76                  result = classLoader.loadClass(className);
77              } else {
78                  result = Class.forName(className);
79              }
80              return Optional.ofNullable(result);
81          } catch (final ClassNotFoundException ex) {
82              return Optional.empty();
83          }
84      }
85  
86      public static void printClassLoader(final Class<?> target) {
87          ClassLoader classLoader = target.getClassLoader();
88          if (classLoader instanceof URLClassLoader) {
89              System.out.println(target.getName()
90                  + "/classLoader = "
91                  + classLoader
92                  + "/URLs/" + Arrays.asList(((URLClassLoader) classLoader).getURLs()));
93          } else {
94              System.out.println(target.getName() + "/classLoader = " + classLoader);
95          }
96      }
97  
98      public static final class FileAndClasspathUtils {
99  
100         private FileAndClasspathUtils() {
101         }
102 
103         /**
104          * Create if not exists.
105          *
106          * @param fileFullPath path
107          */
108         @SneakyThrows
109         public static void ensureFile(final String fileFullPath) {
110             checkState(isNotBlank(fileFullPath), "file undefined. file: %s", fileFullPath);
111             final File file = new File(fileFullPath);
112             if (!file.exists()) {
113                 checkState(file.createNewFile(), "file create failed. file: %s", fileFullPath);
114             }
115             checkState(file.canRead() && file.canWrite(),
116                 "file can't read or write. file: %s", fileFullPath);
117         }
118 
119         /**
120          * Parse file lines.
121          *
122          * @param resource resource
123          * @param mapper   line mapper
124          * @param <T>      type
125          * @return list
126          */
127         @SneakyThrows
128         public static <T> List<T> parseFile(final Resource resource, final Function<String, T> mapper) {
129             return parseFile(resource.getInputStream(), mapper);
130         }
131 
132         /**
133          * Parse file lines.
134          *
135          * @param inputStream stream
136          * @param mapper      line mapper
137          * @param <T>         type
138          * @return list
139          */
140         @SneakyThrows
141         public static <T> List<T> parseFile(final InputStream inputStream, final Function<String, T> mapper) {
142             return IOUtils.readLines(inputStream, UTF_8).stream() //
143                 .filter(line -> isNotBlank(line) && line.trim().charAt(0) != '#') //
144                 .map(mapper) //
145                 .collect(toList());
146         }
147 
148         @SneakyThrows
149         @SuppressWarnings("unchecked")
150         private static <T> Class<T> classForName(final String className) {
151             return (Class<T>) Class.forName(className);
152         }
153 
154         /**
155          * scan.
156          *
157          * @param basePackage   from where (package)
158          * @param includeFilter filter
159          * @param <T>           type
160          * @return classes found
161          */
162         public static <T> Set<Class<T>> scan(final String basePackage, final TypeFilter includeFilter) {
163             checkArgument(isNotBlank(basePackage));
164             // log.info("domainEnums basePackage: {}", basePackage);
165 
166             final ClassPathScanningCandidateProvider provider = new ClassPathScanningCandidateProvider();
167             provider.addIncludeFilter(includeFilter);
168             final Set<BeanDefinition> beanDefinitions =
169                 provider.findCandidateComponents(basePackage.replaceAll("\\.", "/"));
170 
171             final Set<Class<T>> result = newLinkedHashSetWithExpectedSize(beanDefinitions.size());
172             for (final BeanDefinition beanDefinition : beanDefinitions) {
173                 result.add(classForName(beanDefinition.getBeanClassName()));
174             }
175             return result;
176         }
177 
178         public static class InterfaceFilter extends AbstractClassTestingTypeFilter {
179 
180             private final Class<?> type;
181             private final boolean includeInterface;
182 
183             /**
184              * filter find types of interface type.
185              *
186              * @param type             type
187              * @param includeInterface include interface
188              */
189             public InterfaceFilter(final Class<?> type, final boolean includeInterface) {
190                 super();
191                 this.type = type;
192                 this.includeInterface = includeInterface;
193             }
194 
195             @Override
196             protected boolean match(final ClassMetadata metadata) {
197                 return contains(metadata.getInterfaceNames(), this.type.getName())
198                     && (this.includeInterface || !metadata.isInterface());
199             }
200         }
201 
202         public static class AssignableFilter extends AssignableTypeFilter {
203 
204             private final boolean includeInterface;
205             private final boolean includeAbstract;
206 
207             public AssignableFilter(final Class<?> targetType, final boolean includeInterface, final boolean includeAbstract) {
208                 super(targetType);
209                 this.includeInterface = includeInterface;
210                 this.includeAbstract = includeAbstract;
211             }
212 
213             @Override
214             public boolean match(final MetadataReader reader, final MetadataReaderFactory readerFactory) throws IOException {
215                 final ClassMetadata metadata = reader.getClassMetadata();
216                 final boolean match = super.match(reader, readerFactory);
217                 return match && //
218                     (this.includeInterface || !metadata.isInterface()) && //
219                     (this.includeAbstract || !metadata.isAbstract());
220             }
221         }
222 
223         /**
224          * A ClassPathScanningCandidateComponentProvider.
225          *
226          * @author zhanghaolun
227          */
228         public static class ClassPathScanningCandidateProvider
229             extends ClassPathScanningCandidateComponentProvider {
230 
231             /**
232              * new a ClassPathScanningCandidateProvider.
233              */
234             public ClassPathScanningCandidateProvider() {
235                 super(false);
236             }
237 
238             @Override
239             protected boolean isCandidateComponent(final AnnotatedBeanDefinition beanDefinition) {
240                 return beanDefinition.getMetadata().isIndependent();
241             }
242         }
243     }
244 }