diff --git a/annotation/compiler/src/main/java/com/bumptech/glide/annotation/compiler/IndexerGenerator.java b/annotation/compiler/src/main/java/com/bumptech/glide/annotation/compiler/IndexerGenerator.java index cd8038ce84..8a05c9151f 100644 --- a/annotation/compiler/src/main/java/com/bumptech/glide/annotation/compiler/IndexerGenerator.java +++ b/annotation/compiler/src/main/java/com/bumptech/glide/annotation/compiler/IndexerGenerator.java @@ -8,6 +8,7 @@ import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; @@ -46,6 +47,7 @@ */ final class IndexerGenerator { private static final String INDEXER_NAME_PREFIX = "GlideIndexer_"; + private static final int MAXIMUM_FILE_NAME_LENGTH = 255; private final ProcessorUtil processorUtil; IndexerGenerator(ProcessorUtil processorUtil) { @@ -79,7 +81,7 @@ TypeSpec generate(List types) { } } - private static TypeSpec generate( + private TypeSpec generate( List libraryModules, Class annotation) { AnnotationSpec.Builder annotationBuilder = AnnotationSpec.builder(Index.class); @@ -88,15 +90,25 @@ private static TypeSpec generate( annotationBuilder.addMember(value, "$S", ClassName.get(childModule).toString()); } - StringBuilder indexerName = + StringBuilder indexerNameBuilder = new StringBuilder(INDEXER_NAME_PREFIX + annotation.getSimpleName() + "_"); for (TypeElement element : libraryModules) { - indexerName.append(element.getQualifiedName().toString().replace(".", "_")); - indexerName.append("_"); + indexerNameBuilder.append(element.getQualifiedName().toString().replace(".", "_")); + indexerNameBuilder.append("_"); + } + indexerNameBuilder = + new StringBuilder(indexerNameBuilder.substring(0, indexerNameBuilder.length() - 1)); + String indexerName = indexerNameBuilder.toString(); + // If the indexer name has too many packages/modules, it can exceed the file name length + // allowed by the file system, which can break compilation. To avoid that, fall back to a + // deterministic UUID. + if (indexerName.length() >= (MAXIMUM_FILE_NAME_LENGTH - INDEXER_NAME_PREFIX.length())) { + indexerName = + INDEXER_NAME_PREFIX + + UUID.nameUUIDFromBytes(indexerName.getBytes()).toString().replace("-", "_"); } - indexerName = new StringBuilder(indexerName.substring(0, indexerName.length() - 1)); - return TypeSpec.classBuilder(indexerName.toString()) + return TypeSpec.classBuilder(indexerName) .addAnnotation(annotationBuilder.build()) .addModifiers(Modifier.PUBLIC) .build(); diff --git a/annotation/compiler/test/src/test/java/com/bumptech/glide/annotation/compiler/OverlyLongFileNameTest.java b/annotation/compiler/test/src/test/java/com/bumptech/glide/annotation/compiler/OverlyLongFileNameTest.java new file mode 100644 index 0000000000..fa8a63d3c8 --- /dev/null +++ b/annotation/compiler/test/src/test/java/com/bumptech/glide/annotation/compiler/OverlyLongFileNameTest.java @@ -0,0 +1,71 @@ +package com.bumptech.glide.annotation.compiler; + +import static com.google.testing.compile.Compiler.javac; + +import com.bumptech.glide.annotation.compiler.test.CompilationProvider; +import com.google.testing.compile.Compilation; +import com.google.testing.compile.CompilationSubject; +import com.google.testing.compile.JavaFileObjects; +import java.io.File; +import java.io.IOException; +import javax.tools.JavaFileObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Makes sure that we can handle indexers based on long package or file names, or many modules. + * + *

See #4106. + */ +@RunWith(JUnit4.class) +public class OverlyLongFileNameTest implements CompilationProvider { + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); + private Compilation compilation; + private static final String FILE_NAME_LONGER_THAN_255_CHARS = + "SomeReallyReallyRidiculouslyLongFileNameOrPackageNameIGuessThatExceedsTwoHundredAndFiftyFive" + + "CharactersThoughThatsOnlyAroundOneHundredCharactersWhichMeansINeedToKeepTypingToGetTo" + + "TwoHundredAndFiftyFiveSomehowThankfullyOnlyLikeFiftyToGoNowMaybeButNotQuiteYet" + + "SomewhereAroundNowIsProbablyGood"; + + @Before + public void setUp() { + compilation = + javac() + .withProcessors(new GlideAnnotationProcessor()) + .compile( + JavaFileObjects.forSourceLines( + FILE_NAME_LONGER_THAN_255_CHARS, + "package com.bumptech.glide.test;", + "import com.bumptech.glide.annotation.GlideModule;", + "import com.bumptech.glide.module.LibraryGlideModule;", + "@GlideModule", + "public final class " + + FILE_NAME_LONGER_THAN_255_CHARS + + " extends LibraryGlideModule {}")); + } + + @Test + public void compilingLongClassAndOrPackageNameShouldSucceed() throws IOException { + CompilationSubject.assertThat(compilation).succeededWithoutWarnings(); + for (JavaFileObject file : compilation.generatedFiles()) { + temporaryFolder.create(); + String actualFileName = new File(file.getName()).getName(); + if (!actualFileName.startsWith(FILE_NAME_LONGER_THAN_255_CHARS)) { + try { + temporaryFolder.newFile(actualFileName).createNewFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to create: " + actualFileName, e); + } + } + } + } + + @Override + public Compilation getCompilation() { + return compilation; + } +}