From 59c60eb0e5babd7190004f05016ef5faf907079b Mon Sep 17 00:00:00 2001 From: Mark Hiner Date: Wed, 13 Jan 2016 22:05:27 +0100 Subject: [PATCH 1/3] Add Reflections dependency The Reflections project (https://github.com/ronmamo/reflections) adds support for scanning the classpath for various elements, including annotations, types, methods, etc... with pattern filters. --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index fafddc47..49b0276e 100644 --- a/pom.xml +++ b/pom.xml @@ -127,6 +127,7 @@ 1.8 + 0.9.10 @@ -210,6 +211,11 @@ jhotdraw 7.6.0 + + org.reflections + reflections + ${reflections.version} + From 3660b3f0ab390fd6b77a52e9245ac7b387f55acd Mon Sep 17 00:00:00 2001 From: Mark Hiner Date: Wed, 13 Jan 2016 22:06:42 +0100 Subject: [PATCH 2/3] TextEditor: restore addImport function When given a "raw" class (no package), addImport will now iterate over all elements in the core ImageJ packages looking for potential matches to the requested class. All potential matches will be added as imports (e.g. net.imglib2.ImgPlus and net.imglib2.meta.ImgPlus will both be added). If there are no matches, the class will be imported without a package. Addresses http://fiji.sc/bugzilla/show_bug.cgi?id=817 --- .../imagej/ui/swing/script/TextEditor.java | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/imagej/ui/swing/script/TextEditor.java b/src/main/java/net/imagej/ui/swing/script/TextEditor.java index db3a4d62..98b37cf2 100644 --- a/src/main/java/net/imagej/ui/swing/script/TextEditor.java +++ b/src/main/java/net/imagej/ui/swing/script/TextEditor.java @@ -59,6 +59,7 @@ import java.io.Writer; import java.net.URL; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -107,6 +108,10 @@ import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; +import org.reflections.Reflections; +import org.reflections.scanners.SubTypesScanner; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; import org.scijava.Context; import org.scijava.command.CommandService; import org.scijava.event.ContextDisposingEvent; @@ -168,6 +173,7 @@ public class TextEditor extends JFrame implements ActionListener, } private static AbstractTokenMakerFactory tokenMakerFactory = null; + private static Reflections reflections = null; private JTabbedPane tabbed; private JMenuItem newFile, open, save, saveas, compileAndRun, compile, @@ -2064,9 +2070,37 @@ public String getSelectedTextOrAsk(final String label) { public String getSelectedClassNameOrAsk() { String className = getSelectedTextOrAsk("Class name"); if (className != null) className = className.trim(); + return className; } + /** + * Returns the static Reflections instance, constructing it + * if it doesn't already exist. This is to limit the number of + * classpath scans. + * + * @return static {@link Reflections} instance + */ + private static Reflections getReflections() { + if (reflections == null) { + synchronized(TextEditor.class) { + if (reflections == null) { + final Collection packages = new HashSet<>(); + packages.addAll(ClasspathHelper.forPackage("net.imagej")); + packages.addAll(ClasspathHelper.forPackage("org.scijava")); + packages.addAll(ClasspathHelper.forPackage("net.imglib2")); + packages.addAll(ClasspathHelper.forPackage("io.scif")); + packages.addAll(ClasspathHelper.forPackage("sc.fiji")); + packages.addAll(ClasspathHelper.forPackage("ij")); + reflections = new Reflections(new ConfigurationBuilder().setUrls( + packages).setScanners(new SubTypesScanner(false))); + } + } + } + + return reflections; + } + private static void append(final JTextArea textArea, final String text) { final int length = textArea.getDocument().getLength(); textArea.insert(text, length); @@ -2209,7 +2243,38 @@ private void updateGitDirectory() { public void addImport(final String className) { if (className != null) { - new TokenFunctions(getTextArea()).addImport(className.trim()); + + boolean addRaw = true; + + // If there are NO package separators then this is a raw class name. Try + // and find matching packages + + // NB: decided to only look for complete class names without packages. + // Matching "endsWith(className) can produce a plethora of false positives + // which we want to limit, because the current implementation imports + // all matches. + // Some alternatives to consider (including combinations): + // - match *className + // - match *className* + // - match .className* + // - if >1 match show list to the user to choose a "winner" to import + if (!className.contains(".")) { + final String packagedClass = "." + className; + final Reflections refl = TextEditor.getReflections(); + final StringBuilder sb = new StringBuilder(); + + for (final String type : refl.getAllTypes()) { + // look for "blah.className" + if (type.endsWith(packagedClass)) { + addRaw = false; + new TokenFunctions(getTextArea()).addImport(type.trim()); + } + } + } + + // If there was a package separator or no matching packages, import the raw + // class. + if (addRaw) new TokenFunctions(getTextArea()).addImport(className.trim()); } } From aabbc3a21586ee8dcb95021ffc2454285ac43e47 Mon Sep 17 00:00:00 2001 From: Mark Hiner Date: Wed, 13 Jan 2016 22:17:56 +0100 Subject: [PATCH 3/3] TextEditor reflections: add TODO --- src/main/java/net/imagej/ui/swing/script/TextEditor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/net/imagej/ui/swing/script/TextEditor.java b/src/main/java/net/imagej/ui/swing/script/TextEditor.java index 98b37cf2..430a8b11 100644 --- a/src/main/java/net/imagej/ui/swing/script/TextEditor.java +++ b/src/main/java/net/imagej/ui/swing/script/TextEditor.java @@ -2082,6 +2082,10 @@ public String getSelectedClassNameOrAsk() { * @return static {@link Reflections} instance */ private static Reflections getReflections() { + //TODO consider moving this to a service with plugins to determine how the + //packages are filtered. For example having scijava-common on the classpath + //adds org.scijava. Adding imagej-common would add net.imagej to the filter + //list.. etc... if (reflections == null) { synchronized(TextEditor.class) { if (reflections == null) {