From 1655a20505a75cc764ea026f88ee4c8fc3d50780 Mon Sep 17 00:00:00 2001 From: Akhmad Fathonih Date: Tue, 9 Aug 2022 09:42:38 +0900 Subject: [PATCH] fix isModified comparison. While also: 1. Upgrade reflection library due to https://github.com/ronmamo/reflections/issues/273 2. Memoized list of classloaders as it's getting called on each processed file. 3. Added tests for SimpleCache 4. Added tests CodeGenerator fix 5. Minor adjustments --- .../generator/GeneratorFactoryScanner.java | 5 -- .../io/factory/ContextFactoryScanner.java | 18 +++-- graphwalker-java/pom.xml | 4 ++ .../java/source/CodeGenerator.java | 6 +- .../java/source/cache/SimpleCache.java | 5 +- .../graphwalker/java/test/TestExecutor.java | 6 +- .../java/source/CodeGeneratorTest.java | 70 +++++++++++++++++++ .../java/source/cache/SimpleCacheTest.java | 30 ++++++++ pom.xml | 2 +- 9 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 graphwalker-java/src/test/java/org/graphwalker/java/source/CodeGeneratorTest.java create mode 100644 graphwalker-java/src/test/java/org/graphwalker/java/source/cache/SimpleCacheTest.java diff --git a/graphwalker-dsl/src/main/java/org/graphwalker/dsl/antlr/generator/GeneratorFactoryScanner.java b/graphwalker-dsl/src/main/java/org/graphwalker/dsl/antlr/generator/GeneratorFactoryScanner.java index e3b5d6a1d..265d9e081 100644 --- a/graphwalker-dsl/src/main/java/org/graphwalker/dsl/antlr/generator/GeneratorFactoryScanner.java +++ b/graphwalker-dsl/src/main/java/org/graphwalker/dsl/antlr/generator/GeneratorFactoryScanner.java @@ -29,7 +29,6 @@ import org.apache.commons.io.FilenameUtils; import org.graphwalker.core.generator.PathGeneratorBase; import org.reflections.Reflections; -import org.reflections.scanners.SubTypesScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.slf4j.Logger; @@ -47,10 +46,6 @@ private GeneratorFactoryScanner() { private static final Logger logger = LoggerFactory.getLogger(GeneratorFactoryScanner.class); - static { - Reflections.log = null; - } - private static boolean valid(URL url) { String extension = FilenameUtils.getExtension(url.getPath()); return "".equals(extension) || "jar".equals(extension); diff --git a/graphwalker-io/src/main/java/org/graphwalker/io/factory/ContextFactoryScanner.java b/graphwalker-io/src/main/java/org/graphwalker/io/factory/ContextFactoryScanner.java index bf21753ca..18fd515d0 100644 --- a/graphwalker-io/src/main/java/org/graphwalker/io/factory/ContextFactoryScanner.java +++ b/graphwalker-io/src/main/java/org/graphwalker/io/factory/ContextFactoryScanner.java @@ -33,9 +33,12 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import org.apache.commons.io.FilenameUtils; import org.reflections.Reflections; -import org.reflections.scanners.SubTypesScanner; +import org.reflections.scanners.Scanners; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.slf4j.Logger; @@ -56,10 +59,6 @@ private ContextFactoryScanner() { private static final Logger logger = LoggerFactory.getLogger(ContextFactoryScanner.class); - static { - Reflections.log = null; - } - private static Map, ContextFactory> factories = new HashMap<>(); private static boolean valid(URL url) { @@ -80,8 +79,15 @@ private static Collection getUrls() { return filteredUrls; } + private static Reflections getReflections(Collection urls) { + return new Reflections(new ConfigurationBuilder().addUrls(urls).setScanners(Scanners.SubTypes)); + } + public static ContextFactory get(Path path) { - return get(new Reflections(new ConfigurationBuilder().addUrls(getUrls()).addScanners(new SubTypesScanner())), path); + Supplier> memoizedUrls; + memoizedUrls = Suppliers.memoize(ContextFactoryScanner::getUrls); + + return get(getReflections(memoizedUrls.get()), path); } public static ContextFactory get(Reflections reflections, Path path) { diff --git a/graphwalker-java/pom.xml b/graphwalker-java/pom.xml index fc3d1dd1c..6e59153ce 100644 --- a/graphwalker-java/pom.xml +++ b/graphwalker-java/pom.xml @@ -81,6 +81,10 @@ classgraph test + + com.google.guava + guava + diff --git a/graphwalker-java/src/main/java/org/graphwalker/java/source/CodeGenerator.java b/graphwalker-java/src/main/java/org/graphwalker/java/source/CodeGenerator.java index a30a900a5..4f63eb1e8 100644 --- a/graphwalker-java/src/main/java/org/graphwalker/java/source/CodeGenerator.java +++ b/graphwalker-java/src/main/java/org/graphwalker/java/source/CodeGenerator.java @@ -49,8 +49,10 @@ import java.io.IOException; import java.lang.reflect.Modifier; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -91,7 +93,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) thro } private boolean isModified(Path file) throws IOException { - return !Files.getLastModifiedTime(file).equals(cache.get(file).getLastModifiedTime()); + return Files.getLastModifiedTime(file).toMillis() != cache.get(file).getLastModifiedTime().toMillis(); } @Override @@ -111,7 +113,7 @@ private static void write(Context context, SourceFile file) throws IOException { RuntimeModel model = context.getModel(); String source = generator.generate(file, model); Files.createDirectories(file.getOutputPath().getParent()); - Files.write(file.getOutputPath(), source.getBytes(Charset.forName("UTF-8")) + Files.write(file.getOutputPath(), source.getBytes(StandardCharsets.UTF_8) , StandardOpenOption.CREATE , StandardOpenOption.TRUNCATE_EXISTING); } catch (Throwable t) { diff --git a/graphwalker-java/src/main/java/org/graphwalker/java/source/cache/SimpleCache.java b/graphwalker-java/src/main/java/org/graphwalker/java/source/cache/SimpleCache.java index f4eb2c3ce..d114cccf0 100644 --- a/graphwalker-java/src/main/java/org/graphwalker/java/source/cache/SimpleCache.java +++ b/graphwalker-java/src/main/java/org/graphwalker/java/source/cache/SimpleCache.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -60,7 +61,7 @@ public SimpleCache(Path path) { private void read() { if (Files.exists(path)) { try { - String json = new String(Files.readAllBytes(path), Charset.forName("UTF-8")); + String json = new String(Files.readAllBytes(path), StandardCharsets.UTF_8); Map data = gson.fromJson(json, type); storage.putAll(data); } catch (IOException e) { @@ -74,7 +75,7 @@ private void save() { try { String json = gson.toJson(storage); Files.createDirectories(path.getParent()); - Files.write(path, json.getBytes(Charset.forName("UTF-8"))); + Files.write(path, json.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { logger.error(e.getMessage()); throw new CacheException(e); diff --git a/graphwalker-java/src/main/java/org/graphwalker/java/test/TestExecutor.java b/graphwalker-java/src/main/java/org/graphwalker/java/test/TestExecutor.java index 3cfff7152..53a950d64 100644 --- a/graphwalker-java/src/main/java/org/graphwalker/java/test/TestExecutor.java +++ b/graphwalker-java/src/main/java/org/graphwalker/java/test/TestExecutor.java @@ -40,8 +40,7 @@ import org.graphwalker.java.factory.PathGeneratorFactory; import org.graphwalker.java.report.XMLReportGenerator; import org.reflections.Reflections; -import org.reflections.scanners.SubTypesScanner; -import org.reflections.scanners.TypeAnnotationsScanner; +import org.reflections.scanners.Scanners; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.slf4j.Logger; @@ -70,10 +69,9 @@ public final class TestExecutor implements Executor, Observer { private static final Reflections reflections = new Reflections(new ConfigurationBuilder() .addUrls(filter(ClasspathHelper.forJavaClassPath(), ClasspathHelper.forClassLoader())) - .addScanners(new SubTypesScanner(), new TypeAnnotationsScanner())); + .setScanners(Scanners.SubTypes, Scanners.TypesAnnotated)); private static Collection filter(Collection classPath, Collection classLoader) { - Reflections.log = null; List urls = new ArrayList<>(), filteredUrls = new ArrayList<>(); urls.addAll(classPath); urls.addAll(classLoader); diff --git a/graphwalker-java/src/test/java/org/graphwalker/java/source/CodeGeneratorTest.java b/graphwalker-java/src/test/java/org/graphwalker/java/source/CodeGeneratorTest.java new file mode 100644 index 000000000..96c096813 --- /dev/null +++ b/graphwalker-java/src/test/java/org/graphwalker/java/source/CodeGeneratorTest.java @@ -0,0 +1,70 @@ +package org.graphwalker.java.source; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.*; +import java.nio.file.attribute.FileTime; +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class CodeGeneratorTest { + +@Test +public void testOnlyRegenerateWhenSourceIsModified() throws IOException, URISyntaxException { + String tmpdir = System.getProperty("java.io.tmpdir"); + Path inputDir = Files.createTempDirectory(Paths.get(tmpdir), "input").toAbsolutePath(); + Path outputDir = Files.createTempDirectory(Paths.get(tmpdir), "output").toAbsolutePath(); + + // sample file + URL resource = getClass().getClassLoader().getResource("org/graphwalker/java/path with space/MyModel.graphml"); + File testFile = new File(resource.toURI()); + + Files.copy(testFile.toPath(), inputDir.resolve(testFile.getName()), StandardCopyOption.REPLACE_EXISTING); + FileTime sourceLastModified = Files.getLastModifiedTime(inputDir.resolve(testFile.getName())); + + File[] inputFiles = Arrays.stream(inputDir.toFile().listFiles()) + .toArray(File[]::new); + + assertEquals(1, inputFiles.length); + + // run codegenerator for each input files in inputDir + CodeGenerator.generate(inputDir, outputDir); + + // source modified time should not be altered + FileTime sourceLastModifiedDelta = Files.getLastModifiedTime(inputDir.resolve(testFile.getName())); + assertEquals(sourceLastModified.toMillis(), sourceLastModifiedDelta.toMillis()); + + // glob the output files, find the one with the same name as the input file + File[] outputFiles = Arrays.stream(outputDir.toFile().listFiles()) + .filter(f -> f.getName().equals(testFile.getName().replace(".graphml", ".java"))) + .toArray(File[]::new); + + assertEquals(1, outputFiles.length); + assertEquals("MyModel.java", outputFiles[0].getName()); + + // note lst modified time is in milliseconds + long lastModified = outputFiles[0].lastModified(); + + // sleep 5 seconds to make sure the last modified time is different + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // regenerate the file + CodeGenerator.generate(inputDir, outputDir); + + // check that the file was not regenerated + outputFiles = Arrays.stream(outputDir.toFile().listFiles()) + .filter(f -> f.getName().equals(testFile.getName().replace(".graphml", ".java"))) + .toArray(File[]::new); + assertEquals(1, outputFiles.length); + assertEquals(lastModified, outputFiles[0].lastModified()); + } +} diff --git a/graphwalker-java/src/test/java/org/graphwalker/java/source/cache/SimpleCacheTest.java b/graphwalker-java/src/test/java/org/graphwalker/java/source/cache/SimpleCacheTest.java new file mode 100644 index 000000000..089b928d7 --- /dev/null +++ b/graphwalker-java/src/test/java/org/graphwalker/java/source/cache/SimpleCacheTest.java @@ -0,0 +1,30 @@ +package org.graphwalker.java.source.cache; + +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.Assert.*; + +public class SimpleCacheTest { + + @Test + public void get() throws IOException { + SimpleCache cache = new SimpleCache(Paths.get("./")); + // create temporary file + File foo = File.createTempFile("prefix", "suffix"); + foo.deleteOnExit(); + Path key = foo.toPath(); + long lastModified = foo.lastModified(); + cache.add(key, new CacheEntry(lastModified, true)); + CacheEntry cached = cache.get(key); + assertEquals(lastModified, cached.getLastModifiedTime().toMillis()); + assertEquals(true, cached.isGenerated()); + + assertTrue(cache.contains(key)); + } +} diff --git a/pom.xml b/pom.xml index 9fb8e7fe6..44fbd8c1d 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ org.reflections reflections - 0.9.12 + 0.10.2 com.google.code.javaparser