]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add utility for outputting the full declarative syntax of components
authorAleksi Hietanen <aleksi@vaadin.com>
Fri, 14 Oct 2016 08:41:06 +0000 (11:41 +0300)
committerVaadin Code Review <review@vaadin.com>
Mon, 24 Oct 2016 07:55:31 +0000 (07:55 +0000)
Change-Id: I4bc740154ffb5a30892b1859a7550a7aeff94fb3

compatibility-server/src/test/java/com/vaadin/tests/server/ClasspathHelper.java [new file with mode: 0644]
compatibility-server/src/test/java/com/vaadin/tests/server/ComponentDesignWriterUtility.java [new file with mode: 0644]
compatibility-server/src/test/java/com/vaadin/tests/server/DeprecatedTest.java
compatibility-server/src/test/java/com/vaadin/v7/tests/VaadinClasses.java
server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java
server/src/main/java/com/vaadin/ui/declarative/DesignContext.java

diff --git a/compatibility-server/src/test/java/com/vaadin/tests/server/ClasspathHelper.java b/compatibility-server/src/test/java/com/vaadin/tests/server/ClasspathHelper.java
new file mode 100644 (file)
index 0000000..d327181
--- /dev/null
@@ -0,0 +1,121 @@
+package com.vaadin.tests.server;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Allows to get classes from the current classpath using classes FQN filter.
+ * <p>
+ * The methods in the class return all real (not anonymous and not private)
+ * classes from the filtered classpath.
+ * 
+ * @author Vaadin Ltd
+ *
+ */
+class ClasspathHelper {
+
+    private final Predicate<String> skipClassesFilter;
+
+    ClasspathHelper(Predicate<String> skipClassesFilter) {
+        this.skipClassesFilter = skipClassesFilter;
+    }
+
+    Stream<Class<?>> getVaadinClassesFromClasspath(
+            Predicate<String> classpathFilter,
+            Predicate<Class<?>> classFilter) {
+        return getRawClasspathEntries().stream().filter(classpathFilter)
+                .map(File::new).map(file -> getVaadinClassesFromFile(file))
+                .flatMap(List::stream).filter(classFilter)
+                .filter(cls -> !cls.isSynthetic() && !cls.isAnonymousClass()
+                        && !Modifier.isPrivate(cls.getModifiers()));
+
+    }
+
+    Stream<Class<?>> getVaadinClassesFromClasspath(
+            Predicate<String> classpathFilter) {
+        return getVaadinClassesFromClasspath(classpathFilter, cls -> true);
+    }
+
+    private List<Class<?>> getVaadinClassesFromFile(File classesRoot) {
+        try {
+            if (classesRoot.isDirectory()) {
+                return Files.walk(classesRoot.toPath())
+                        .filter(Files::isRegularFile)
+                        .filter(path -> path.toFile().getName()
+                                .endsWith(".class"))
+                        .filter(path -> classesRoot.toPath().relativize(path)
+                                .toString().contains("com/vaadin/"))
+                        .map(path -> getClassFromFile(path,
+                                classesRoot.toPath()))
+                        .filter(Objects::nonNull).collect(Collectors.toList());
+            } else if (classesRoot.getName().toLowerCase(Locale.ENGLISH)
+                    .endsWith(".jar")) {
+                URI uri = URI.create("jar:file:" + classesRoot.getPath());
+                Path root = FileSystems
+                        .newFileSystem(uri, Collections.emptyMap())
+                        .getPath("/");
+                return Files.walk(root).filter(Files::isRegularFile)
+                        .filter(path -> path.toUri().getSchemeSpecificPart()
+                                .endsWith(".class"))
+                        .filter(path -> root.relativize(path).toString()
+                                .contains("com/vaadin/"))
+                        .map(path -> getClassFromFile(path, root))
+                        .filter(Objects::nonNull).collect(Collectors.toList());
+            }
+            return null;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private Class<?> getClassFromFile(Path path, Path root) {
+        Path relative = root.relativize(path);
+        String name = relative.toString();
+        name = name.substring(0, name.length() - ".class".length());
+        name = name.replace('/', '.');
+        if (skipClassesFilter.test(name)) {
+            return null;
+        }
+        try {
+            return Class.forName(name, false, getClass().getClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private final static List<String> getRawClasspathEntries() {
+        List<String> locations = new ArrayList<>();
+
+        String pathSep = System.getProperty("path.separator");
+        String classpath = System.getProperty("java.class.path");
+
+        if (classpath.startsWith("\"")) {
+            classpath = classpath.substring(1);
+        }
+        if (classpath.endsWith("\"")) {
+            classpath = classpath.substring(0, classpath.length() - 1);
+        }
+
+        String[] split = classpath.split(pathSep);
+        for (int i = 0; i < split.length; i++) {
+            String classpathEntry = split[i];
+            locations.add(classpathEntry);
+        }
+
+        return locations;
+    }
+
+}
diff --git a/compatibility-server/src/test/java/com/vaadin/tests/server/ComponentDesignWriterUtility.java b/compatibility-server/src/test/java/com/vaadin/tests/server/ComponentDesignWriterUtility.java
new file mode 100644 (file)
index 0000000..15ae1c9
--- /dev/null
@@ -0,0 +1,204 @@
+package com.vaadin.tests.server;
+
+import java.io.File;
+import java.lang.reflect.Modifier;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.navigator.Navigator;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DragAndDropWrapper;
+import com.vaadin.ui.components.colorpicker.ColorPickerGradient;
+import com.vaadin.ui.components.colorpicker.ColorPickerGrid;
+import com.vaadin.ui.components.colorpicker.ColorPickerHistory;
+import com.vaadin.ui.components.colorpicker.ColorPickerPopup;
+import com.vaadin.ui.components.colorpicker.ColorPickerPreview;
+import com.vaadin.ui.components.colorpicker.ColorPickerSelect;
+import com.vaadin.ui.declarative.Design;
+import com.vaadin.ui.declarative.DesignAttributeHandler;
+import com.vaadin.ui.declarative.DesignContext;
+
+/**
+ * Utility class for outputting the declarative syntax of Vaadin components.
+ */
+public class ComponentDesignWriterUtility {
+
+    private static final Set<String> WHITE_LIST_FQNS = new HashSet<>();
+    static {
+        WHITE_LIST_FQNS.add(DragAndDropWrapper.class.getName());
+        WHITE_LIST_FQNS.add(Navigator.EmptyView.class.getName());
+
+        WHITE_LIST_FQNS.add(ColorPickerGradient.class.getName());
+        WHITE_LIST_FQNS.add(ColorPickerPopup.class.getName());
+        WHITE_LIST_FQNS.add(ColorPickerPreview.class.getName());
+        WHITE_LIST_FQNS.add(ColorPickerGrid.class.getName());
+        WHITE_LIST_FQNS.add(ColorPickerSelect.class.getName());
+        WHITE_LIST_FQNS.add(ColorPickerHistory.class.getName());
+
+        WHITE_LIST_FQNS
+                .add(com.vaadin.v7.ui.components.colorpicker.ColorPickerGradient.class
+                        .getName());
+        WHITE_LIST_FQNS
+                .add(com.vaadin.v7.ui.components.colorpicker.ColorPickerPopup.class
+                        .getName());
+        WHITE_LIST_FQNS
+                .add(com.vaadin.v7.ui.components.colorpicker.ColorPickerPreview.class
+                        .getName());
+        WHITE_LIST_FQNS
+                .add(com.vaadin.v7.ui.components.colorpicker.ColorPickerGrid.class
+                        .getName());
+        WHITE_LIST_FQNS
+                .add(com.vaadin.v7.ui.components.colorpicker.ColorPickerSelect.class
+                        .getName());
+        WHITE_LIST_FQNS
+                .add(com.vaadin.v7.ui.components.colorpicker.ColorPickerHistory.class
+                        .getName());
+
+        // ==================================================================
+        // Classes that cannot be loaded
+        // ==================================================================
+        WHITE_LIST_FQNS.add(
+                "com.vaadin.server.communication.PushAtmosphereHandler$AtmosphereResourceListener");
+        WHITE_LIST_FQNS
+                .add("com.vaadin.server.communication.PushAtmosphereHandler");
+        WHITE_LIST_FQNS
+                .add("com.vaadin.server.communication.PushRequestHandler$2");
+        WHITE_LIST_FQNS.add("com.vaadin.server.LegacyVaadinPortlet");
+        WHITE_LIST_FQNS.add("com.vaadin.server.RestrictedRenderResponse");
+        WHITE_LIST_FQNS
+                .add("com.vaadin.server.VaadinPortlet$VaadinGateInRequest");
+        WHITE_LIST_FQNS.add(
+                "com.vaadin.server.VaadinPortlet$VaadinHttpAndPortletRequest");
+        WHITE_LIST_FQNS
+                .add("com.vaadin.server.VaadinPortlet$VaadinLiferayRequest");
+        WHITE_LIST_FQNS.add(
+                "com.vaadin.server.VaadinPortlet$VaadinWebLogicPortalRequest");
+        WHITE_LIST_FQNS.add(
+                "com.vaadin.server.VaadinPortlet$VaadinWebSpherePortalRequest");
+        WHITE_LIST_FQNS.add("com.vaadin.server.VaadinPortlet");
+        WHITE_LIST_FQNS.add("com.vaadin.server.VaadinPortletRequest");
+    }
+
+    private static final Document document = new Document("");
+    private static final DesignContext designContext = new DesignContext(
+            document);
+
+    @SafeVarargs
+    public static List<String> getDeclarativeSyntax(
+            Class<? extends Component>... components) {
+        return getDeclarativeSyntax(Arrays.asList(components));
+    }
+
+    public static List<String> getDeclarativeSyntax(
+            List<Class<? extends Component>> components) {
+        DesignAttributeHandler.setWriteDefaultValues(true);
+
+        List<String> declarativeStrings = components.stream()
+                .map(ComponentDesignWriterUtility::getDeclarativeSyntax)
+                .collect(Collectors.toList());
+
+        DesignAttributeHandler.setWriteDefaultValues(false);
+        return declarativeStrings;
+    }
+
+    @Test
+    public void vaadin8ComponentsElementStartsWithVaadinPrefix()
+            throws URISyntaxException {
+        Assert.assertTrue(getVaadin8Components().stream()
+                .map(ComponentDesignWriterUtility::getDeclarativeSyntax)
+                .allMatch(element -> element.startsWith("<vaadin-")));
+    }
+
+    @Test
+    public void vaadin7ComponentsElementStartsWithVaadinPrefix()
+            throws URISyntaxException {
+        Assert.assertTrue(getVaadin7Components().stream()
+                .map(ComponentDesignWriterUtility::getDeclarativeSyntax)
+                .allMatch(element -> element.startsWith("<vaadin7-")));
+    }
+
+    private static String getDeclarativeSyntax(
+            Class<? extends Component> componentClass) {
+        try {
+            Component component = componentClass.newInstance();
+            Element element = document.createElement(Design.getComponentMapper()
+                    .componentToTag(component, designContext));
+            component.writeDesign(element, designContext);
+            return element.toString();
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Could not write the declarative syntax for component "
+                            + componentClass.getName(),
+                    e);
+        }
+    }
+
+    public static void main(String[] args) throws URISyntaxException {
+        System.out.println("Vaadin 8 components:");
+        printFullDeclarativeSyntax(getVaadin8Components());
+
+        System.out.println("Vaadin 7 components:");
+        printFullDeclarativeSyntax(getVaadin7Components());
+
+        System.out.println("\nClases that are explicitely excluded from "
+                + "the design support introspection:");
+        WHITE_LIST_FQNS.forEach(System.out::println);
+    }
+
+    private static void printFullDeclarativeSyntax(
+            List<Class<? extends Component>> components) {
+        DesignAttributeHandler.setWriteDefaultValues(true);
+        components.stream().forEach(component -> System.out
+                .println(getDeclarativeSyntax(component)));
+        DesignAttributeHandler.setWriteDefaultValues(false);
+    }
+
+    private static List<Class<? extends Component>> getVaadin8Components()
+            throws URISyntaxException {
+        List<Class<? extends Component>> vaadin8Components = getVaadinComponentsFromClasspath(
+                "/server/target/classes");
+        if (vaadin8Components.isEmpty()) {
+            throw new RuntimeException(
+                    "No vaadin 8 components found on your classpath.");
+        }
+        return vaadin8Components;
+    }
+
+    private static List<Class<? extends Component>> getVaadin7Components()
+            throws URISyntaxException {
+        List<Class<? extends Component>> vaadin7Components = getVaadinComponentsFromClasspath(
+                "compatibility-server");
+        if (vaadin7Components.isEmpty()) {
+            throw new RuntimeException(
+                    "No vaadin 7 components found on your classpath.");
+        }
+        return vaadin7Components;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static List<Class<? extends Component>> getVaadinComponentsFromClasspath(
+            String classpathFilter) throws URISyntaxException {
+        File testRoot = new File(
+                ComponentDesignWriterUtility.class.getResource("/").toURI());
+        List<Class<? extends Component>> classes = new ClasspathHelper(
+                WHITE_LIST_FQNS::contains).getVaadinClassesFromClasspath(
+                        entry -> entry.contains(classpathFilter)
+                                && !testRoot.equals(new File(entry)),
+                        cls -> Component.class.isAssignableFrom(cls)
+                                && !cls.isInterface()
+                                && !Modifier.isAbstract(cls.getModifiers()))
+                        .map(cls -> (Class<? extends Component>) cls)
+                        .collect(Collectors.toList());
+        return classes;
+    }
+
+}
index e8475b6750f35894b96ea894f1ca7161fe902fa4..671fc65080bb5cd3911c4496c5c0901a4a241104 100644 (file)
 package com.vaadin.tests.server;
 
 import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Modifier;
-import java.net.URI;
 import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.stream.Collectors;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -39,86 +28,24 @@ import org.junit.Test;
  */
 public class DeprecatedTest {
 
-    private static String CLASS_SUFFIX = ".class";
-
     @Test
     public void allTypesAreDeprecated() throws URISyntaxException {
-        URL url = DeprecatedTest.class.getResource("/");
-        File file = new File(url.toURI());
-        List<File> classpath = getRawClasspathEntries().stream()
-                .filter(entry -> entry.contains("compatibility-server"))
-                .map(File::new).filter(fileEntry -> !fileEntry.equals(file))
-                .collect(Collectors.toList());
-        Assert.assertFalse(classpath.isEmpty());
-        classpath.forEach(this::checkDeprecatedClasses);
-    }
-
-    private void checkDeprecatedClasses(File classesRoot) {
-        try {
-            if (classesRoot.isDirectory()) {
-                Files.walk(classesRoot.toPath()).filter(Files::isRegularFile)
-                        .filter(path -> path.toFile().getName()
-                                .endsWith(CLASS_SUFFIX))
-                        .forEach(path -> checkDeprecatedClass(path,
-                                classesRoot.toPath()));
-            } else if (classesRoot.getName().toLowerCase(Locale.ENGLISH)
-                    .endsWith(".jar")) {
-                URI uri = URI.create("jar:file:" + classesRoot.getPath());
-                Path root = FileSystems
-                        .newFileSystem(uri, Collections.emptyMap())
-                        .getPath("/");
-                Files.walk(root).filter(Files::isRegularFile)
-                        .filter(path -> path.toUri().getSchemeSpecificPart()
-                                .endsWith(CLASS_SUFFIX))
-                        .forEach(path -> checkDeprecatedClass(path, root));
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private void checkDeprecatedClass(Path path, Path root) {
-        Path relative = root.relativize(path);
-        String name = relative.toString();
-        name = name.substring(0, name.length() - CLASS_SUFFIX.length());
-        name = name.replace('/', '.');
-        try {
-            Class<?> clazz = Class.forName(name);
-            if (clazz.isSynthetic() || clazz.isAnonymousClass()) {
-                return;
-            }
-            if (Modifier.isPrivate(clazz.getModifiers())) {
-                return;
-            }
-            Assert.assertNotNull(
-                    "Class " + clazz
-                            + " is in compatability package and it's not deprecated",
-                    clazz.getAnnotation(Deprecated.class));
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException(e);
-        }
+        AtomicInteger count = new AtomicInteger(0);
+
+        File testRoot = new File(DeprecatedTest.class.getResource("/").toURI());
+
+        new ClasspathHelper(fqn -> false)
+                .getVaadinClassesFromClasspath(
+                        entry -> entry.contains("compatibility-server")
+                                && !testRoot.equals(new File(entry)))
+                .forEach(cls -> {
+                    count.incrementAndGet();
+                    Assert.assertNotNull(
+                            "Class " + cls
+                                    + " is in compatability package and it's not deprecated",
+                            cls.getAnnotation(Deprecated.class));
+                });
+        Assert.assertTrue(count.get() > 0);
     }
 
-    private final static List<String> getRawClasspathEntries() {
-        // try to keep the order of the classpath
-        List<String> locations = new ArrayList<>();
-
-        String pathSep = System.getProperty("path.separator");
-        String classpath = System.getProperty("java.class.path");
-
-        if (classpath.startsWith("\"")) {
-            classpath = classpath.substring(1);
-        }
-        if (classpath.endsWith("\"")) {
-            classpath = classpath.substring(0, classpath.length() - 1);
-        }
-
-        String[] split = classpath.split(pathSep);
-        for (int i = 0; i < split.length; i++) {
-            String classpathEntry = split[i];
-            locations.add(classpathEntry);
-        }
-
-        return locations;
-    }
 }
index b37f1bbe863d32ebe22ee3650c91781201f19a61..251f8b0223f77fdb1e8a06ca77bc52627b96eed0 100644 (file)
@@ -3,6 +3,7 @@ package com.vaadin.v7.tests;
 import java.io.IOException;
 import java.util.List;
 
+import com.vaadin.ui.Component;
 import com.vaadin.v7.ui.Field;
 
 @SuppressWarnings("deprecation")
@@ -11,11 +12,20 @@ public class VaadinClasses {
     public static List<Class<? extends Field>> getFields() {
         try {
             return com.vaadin.tests.VaadinClasses.findClasses(Field.class,
-                    "com.vaadin.ui");
+                    "com.vaadin.v7.ui");
         } catch (IOException e) {
             e.printStackTrace();
             return null;
         }
     }
 
+    public static List<Class<? extends Component>> getComponents() {
+        try {
+            return com.vaadin.tests.VaadinClasses.findClasses(Component.class,
+                    "com.vaadin.v7.ui");
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    "Could not find all Vaadin component classes", e);
+        }
+    }
 }
index a70ab256e1147e98fd14924847ebb8e21394db51..4290620051ec1e1f59dfe745d7c42066e45367a2 100644 (file)
@@ -60,6 +60,21 @@ public class DesignAttributeHandler implements Serializable {
     // translates string <-> object
     private static DesignFormatter FORMATTER = new DesignFormatter();
 
+    private static boolean writeDefaultValues = false;
+
+    /**
+     * Set whether default attribute values should be written by the
+     * {@code DesignAttributeHandler#writeAttribute(String, Attributes, Object, Object, Class)}
+     * method. Default is {@code false}.
+     *
+     * @param value
+     *            {@code true} to write default values of attributes,
+     *            {@code false} to disable writing of default values
+     */
+    public static void setWriteDefaultValues(boolean value) {
+        writeDefaultValues = value;
+    }
+
     /**
      * Returns the currently used formatter. All primitive types and all types
      * needed by Vaadin components are handled by that formatter.
@@ -238,7 +253,7 @@ public class DesignAttributeHandler implements Serializable {
             throw new IllegalArgumentException(
                     "input type: " + inputType.getName() + " not supported");
         }
-        if (!SharedUtil.equals(value, defaultValue)) {
+        if (writeDefaultValues || !SharedUtil.equals(value, defaultValue)) {
             String attributeValue = toAttributeValue(inputType, value);
             if ("".equals(attributeValue) && (inputType == boolean.class
                     || inputType == Boolean.class)) {
index 35145c45fbb90a3d11523eafdde3b4676a91f152..ecbd5e638c35dd19509a6c61ec8fc6c0fc4777c3 100644 (file)
@@ -827,8 +827,7 @@ public class DesignContext implements Serializable {
             String value) {
         Map<String, String> map = customAttributes.get(component);
         if (map == null) {
-            customAttributes.put(component,
-                    map = new HashMap<>());
+            customAttributes.put(component, map = new HashMap<>());
         }
         map.put(attribute, value);
     }