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
47
48
49
50
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
105
106
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
121
122
123
124
125
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
134
135
136
137
138
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
156
157
158
159
160
161
162 public static <T> Set<Class<T>> scan(final String basePackage, final TypeFilter includeFilter) {
163 checkArgument(isNotBlank(basePackage));
164
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
185
186
187
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
225
226
227
228 public static class ClassPathScanningCandidateProvider
229 extends ClassPathScanningCandidateComponentProvider {
230
231
232
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 }