From: Aleksi Hietanen Date: Fri, 14 Oct 2016 08:41:06 +0000 (+0300) Subject: Add utility for outputting the full declarative syntax of components X-Git-Tag: 8.0.0.alpha6~56 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2cdb3b39329232dcefee2ae61ded92f2c3fe54b0;p=vaadin-framework.git Add utility for outputting the full declarative syntax of components Change-Id: I4bc740154ffb5a30892b1859a7550a7aeff94fb3 --- 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 index 0000000000..d32718196b --- /dev/null +++ b/compatibility-server/src/test/java/com/vaadin/tests/server/ClasspathHelper.java @@ -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. + *

+ * 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 skipClassesFilter; + + ClasspathHelper(Predicate skipClassesFilter) { + this.skipClassesFilter = skipClassesFilter; + } + + Stream> getVaadinClassesFromClasspath( + Predicate classpathFilter, + Predicate> 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> getVaadinClassesFromClasspath( + Predicate classpathFilter) { + return getVaadinClassesFromClasspath(classpathFilter, cls -> true); + } + + private List> 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 getRawClasspathEntries() { + List 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 index 0000000000..15ae1c9cf4 --- /dev/null +++ b/compatibility-server/src/test/java/com/vaadin/tests/server/ComponentDesignWriterUtility.java @@ -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 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 getDeclarativeSyntax( + Class... components) { + return getDeclarativeSyntax(Arrays.asList(components)); + } + + public static List getDeclarativeSyntax( + List> components) { + DesignAttributeHandler.setWriteDefaultValues(true); + + List 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(" element.startsWith(" 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> components) { + DesignAttributeHandler.setWriteDefaultValues(true); + components.stream().forEach(component -> System.out + .println(getDeclarativeSyntax(component))); + DesignAttributeHandler.setWriteDefaultValues(false); + } + + private static List> getVaadin8Components() + throws URISyntaxException { + List> vaadin8Components = getVaadinComponentsFromClasspath( + "/server/target/classes"); + if (vaadin8Components.isEmpty()) { + throw new RuntimeException( + "No vaadin 8 components found on your classpath."); + } + return vaadin8Components; + } + + private static List> getVaadin7Components() + throws URISyntaxException { + List> 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> getVaadinComponentsFromClasspath( + String classpathFilter) throws URISyntaxException { + File testRoot = new File( + ComponentDesignWriterUtility.class.getResource("/").toURI()); + List> 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) cls) + .collect(Collectors.toList()); + return classes; + } + +} diff --git a/compatibility-server/src/test/java/com/vaadin/tests/server/DeprecatedTest.java b/compatibility-server/src/test/java/com/vaadin/tests/server/DeprecatedTest.java index e8475b6750..671fc65080 100644 --- a/compatibility-server/src/test/java/com/vaadin/tests/server/DeprecatedTest.java +++ b/compatibility-server/src/test/java/com/vaadin/tests/server/DeprecatedTest.java @@ -16,19 +16,8 @@ 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 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 getRawClasspathEntries() { - // try to keep the order of the classpath - List 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/v7/tests/VaadinClasses.java b/compatibility-server/src/test/java/com/vaadin/v7/tests/VaadinClasses.java index b37f1bbe86..251f8b0223 100644 --- a/compatibility-server/src/test/java/com/vaadin/v7/tests/VaadinClasses.java +++ b/compatibility-server/src/test/java/com/vaadin/v7/tests/VaadinClasses.java @@ -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> 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> 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); + } + } } diff --git a/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java b/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java index a70ab256e1..4290620051 100644 --- a/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java +++ b/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java @@ -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)) { diff --git a/server/src/main/java/com/vaadin/ui/declarative/DesignContext.java b/server/src/main/java/com/vaadin/ui/declarative/DesignContext.java index 35145c45fb..ecbd5e638c 100644 --- a/server/src/main/java/com/vaadin/ui/declarative/DesignContext.java +++ b/server/src/main/java/com/vaadin/ui/declarative/DesignContext.java @@ -827,8 +827,7 @@ public class DesignContext implements Serializable { String value) { Map map = customAttributes.get(component); if (map == null) { - customAttributes.put(component, - map = new HashMap<>()); + customAttributes.put(component, map = new HashMap<>()); } map.put(attribute, value); }