aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java
diff options
context:
space:
mode:
authorGravatar janakr <janakr@google.com>2018-02-26 12:52:13 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-26 12:54:12 -0800
commit0b59342ad5e4935368c790799dfc9c7b192b6225 (patch)
treed48bb8696e508a91f71e0c25777d52cf38032f25 /src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java
parente5118c5da8255662caefd4a5e1cb5c37d9a19466 (diff)
Allow @AutoCodec to tag static final fields, and generate a "pointer" class that has a single static INSTANCE field pointing back to the target field, so that serialization can grab it.
PiperOrigin-RevId: 187065629
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java70
1 files changed, 57 insertions, 13 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java
index ce6db63d63..1b387134a5 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/CodecScanner.java
@@ -17,14 +17,19 @@ package com.google.devtools.build.lib.skyframe.serialization;
import com.google.common.base.Preconditions;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.RegisteredSingletonDoNotUse;
import java.io.IOException;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
+import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
@@ -52,7 +57,8 @@ public class CodecScanner {
throws IOException, ReflectiveOperationException {
ArrayList<Class<? extends ObjectCodec<?>>> codecs = new ArrayList<>();
ArrayList<Class<? extends CodecRegisterer<?>>> registerers = new ArrayList<>();
- scanCodecs(packagePrefix)
+ List<ClassInfo> classInfos = getClassInfos(packagePrefix).collect(Collectors.toList());
+ getCodecs(classInfos)
.forEach(
type -> {
if (!ObjectCodec.class.equals(type) && ObjectCodec.class.isAssignableFrom(type)) {
@@ -63,8 +69,40 @@ public class CodecScanner {
registerers.add((Class<? extends CodecRegisterer<?>>) type);
}
});
-
ObjectCodecRegistry.Builder builder = ObjectCodecRegistry.newBuilder();
+ getMatchingClasses(
+ classInfos,
+ classInfo ->
+ classInfo
+ .getSimpleName()
+ .endsWith(CodecScanningConstants.REGISTERED_SINGLETON_SUFFIX))
+ .forEach(
+ type -> {
+ if (!RegisteredSingletonDoNotUse.class.isAssignableFrom(type)) {
+ return;
+ }
+ Field field;
+ try {
+ field =
+ type.getDeclaredField(
+ CodecScanningConstants.REGISTERED_SINGLETON_INSTANCE_VAR_NAME);
+ } catch (NoSuchFieldException e) {
+ throw new IllegalStateException(
+ type
+ + " inherits from "
+ + RegisteredSingletonDoNotUse.class
+ + " but does not have a field "
+ + CodecScanningConstants.REGISTERED_SINGLETON_INSTANCE_VAR_NAME,
+ e);
+ }
+ try {
+ builder.addConstant(field.get(null));
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException(
+ "Could not access field " + field + " for " + type, e);
+ }
+ });
+
HashSet<Class<? extends ObjectCodec<?>>> alreadyRegistered =
runRegisterers(builder, registerers);
@@ -181,21 +219,27 @@ public class CodecScanner {
return -1;
}
- /**
- * Returns a stream of likely codec and registerer implementations.
- *
- * <p>Caller should do additional checks as this method only performs string matching.
- *
- * @param packagePrefix emits only classes in packages having this prefix
- */
- private static Stream<Class<?>> scanCodecs(String packagePrefix) throws IOException {
+ private static Stream<ClassInfo> getClassInfos(String packagePrefix) throws IOException {
return ClassPath.from(ClassLoader.getSystemClassLoader())
.getResources()
.stream()
.filter(r -> r instanceof ClassInfo)
.map(r -> (ClassInfo) r)
- .filter(c -> c.getPackageName().startsWith(packagePrefix))
- .filter(c -> c.getName().endsWith("Codec") || c.getName().endsWith("CodecRegisterer"))
- .map(c -> c.load());
+ .filter(c -> c.getPackageName().startsWith(packagePrefix));
+ }
+
+ /**
+ * Returns a stream of likely codec and registerer implementations.
+ *
+ * <p>Caller should do additional checks as this method only performs string matching.
+ */
+ private static Stream<Class<?>> getCodecs(List<ClassInfo> classInfos) {
+ return getMatchingClasses(
+ classInfos, c -> c.getName().endsWith("Codec") || c.getName().endsWith("CodecRegisterer"));
+ }
+
+ private static Stream<Class<?>> getMatchingClasses(
+ List<ClassInfo> classInfos, Predicate<ClassInfo> predicate) {
+ return classInfos.stream().filter(predicate).map(ClassInfo::load);
}
}