From 04fa565f7857896b6c1d55b6b258968b7473bdcd Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 11 Jul 2016 16:05:30 +0300 Subject: [PATCH] Support static inner classes when reading/writing declarative files (#20038) Uses outer class name as package name for static inner classes. When reading, there is no way to know that the class is an inner class so only when creating a class fails, an inner class is tried as a backup. Change-Id: I3ebf5b2da11384f9dc64072a3dc8ee132607237c --- .../com/vaadin/ui/declarative/Design.java | 35 +++++++++++++++-- .../design/InnerClassDesignReadWriteTest.java | 38 +++++++++++++++++++ .../design/UPPERCASE/InUpperCasePackage.java | 7 ++++ 3 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 server/src/test/java/com/vaadin/tests/design/InnerClassDesignReadWriteTest.java create mode 100644 server/src/test/java/com/vaadin/tests/design/UPPERCASE/InUpperCasePackage.java diff --git a/server/src/main/java/com/vaadin/ui/declarative/Design.java b/server/src/main/java/com/vaadin/ui/declarative/Design.java index 5ce1f5dc60..a12cd65557 100644 --- a/server/src/main/java/com/vaadin/ui/declarative/Design.java +++ b/server/src/main/java/com/vaadin/ui/declarative/Design.java @@ -22,6 +22,7 @@ import java.io.OutputStream; import java.io.Serializable; import java.lang.annotation.Annotation; import java.util.Collection; +import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; @@ -146,9 +147,24 @@ public class Design implements Serializable { @Override public Component createComponent(String fullyQualifiedClassName, DesignContext context) { - Class componentClass = resolveComponentClass( - fullyQualifiedClassName, context); + Class componentClass; + try { + componentClass = resolveComponentClass(fullyQualifiedClassName, + context); + } catch (DesignException e) { + // Try with an inner class. + int lastDot = fullyQualifiedClassName.lastIndexOf('.'); + if (lastDot != -1) { + String qualifiedInnerClassName = fullyQualifiedClassName + .substring(0, lastDot) + + "$" + + fullyQualifiedClassName.substring(lastDot + 1); + return createComponent(qualifiedInnerClassName, context); + } else { + throw e; + } + } assert Component.class.isAssignableFrom(componentClass) : "resolveComponentClass returned " + componentClass + " which is not a Vaadin Component class"; @@ -234,10 +250,11 @@ public class Design implements Serializable { @Override public String componentToTag(Component component, DesignContext context) { Class componentClass = component.getClass(); - String packageName = componentClass.getPackage().getName(); + String packageName = getPackageName(componentClass); String prefix = context.getPackagePrefix(packageName); if (prefix == null) { - prefix = packageName.replace('.', '_'); + prefix = packageName.replace('.', '_').toLowerCase( + Locale.ENGLISH); context.addPackagePrefix(prefix, packageName); } prefix = prefix + "-"; @@ -248,6 +265,16 @@ public class Design implements Serializable { return tagName; } + private String getPackageName(Class componentClass) { + if (componentClass.isMemberClass()) { + Class enclosingClass = componentClass.getEnclosingClass(); + return getPackageName(enclosingClass) + "." + + enclosingClass.getSimpleName(); + } else { + return componentClass.getPackage().getName(); + } + } + /** * Creates the name of the html tag corresponding to the given class * name. The name is derived by converting each uppercase letter to diff --git a/server/src/test/java/com/vaadin/tests/design/InnerClassDesignReadWriteTest.java b/server/src/test/java/com/vaadin/tests/design/InnerClassDesignReadWriteTest.java new file mode 100644 index 0000000000..e42a89e98d --- /dev/null +++ b/server/src/test/java/com/vaadin/tests/design/InnerClassDesignReadWriteTest.java @@ -0,0 +1,38 @@ +package com.vaadin.tests.design; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.junit.Test; + +import com.vaadin.tests.design.InnerClassDesignReadWriteTest.Foo.StaticInnerInner; +import com.vaadin.tests.design.UPPERCASE.InUpperCasePackage; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.declarative.Design; + +public class InnerClassDesignReadWriteTest { + @Test + public void testWritingAndReadingBackInnerClass() throws IOException { + VerticalLayout vl = new VerticalLayout(); + vl.addComponent(new StaticInner()); + vl.addComponent(new StaticInnerInner()); + vl.addComponent(new InUpperCasePackage()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Design.write(vl, baos); + Design.read(new ByteArrayInputStream(baos.toByteArray())); + } + + public static class StaticInner extends GridLayout { + } + + public static class Foo { + public static class StaticInnerInner extends HorizontalLayout { + + } + } + +} diff --git a/server/src/test/java/com/vaadin/tests/design/UPPERCASE/InUpperCasePackage.java b/server/src/test/java/com/vaadin/tests/design/UPPERCASE/InUpperCasePackage.java new file mode 100644 index 0000000000..255581d9f3 --- /dev/null +++ b/server/src/test/java/com/vaadin/tests/design/UPPERCASE/InUpperCasePackage.java @@ -0,0 +1,7 @@ +package com.vaadin.tests.design.UPPERCASE; + +import com.vaadin.ui.VerticalLayout; + +public class InUpperCasePackage extends VerticalLayout { + +} \ No newline at end of file -- 2.39.5