From bedbe2bf818385bb2356224a40c49de8f8056749 Mon Sep 17 00:00:00 2001 From: Mika Murtojarvi Date: Wed, 17 Dec 2014 18:10:09 +0200 Subject: [PATCH] Allow reading and writing empty designs (#7749). Change-Id: Id66201d040d07f0e0d731418624c9b702b2d0d3b --- .../src/com/vaadin/ui/declarative/Design.java | 33 +++++--- .../vaadin/ui/declarative/DesignContext.java | 2 +- .../server/component/TestReadEmptyDesign.java | 78 +++++++++++++++++++ .../component/TestWriteEmptyDesign.java | 58 ++++++++++++++ 4 files changed, 159 insertions(+), 12 deletions(-) create mode 100644 server/tests/src/com/vaadin/tests/server/component/TestReadEmptyDesign.java create mode 100644 server/tests/src/com/vaadin/tests/server/component/TestWriteEmptyDesign.java diff --git a/server/src/com/vaadin/ui/declarative/Design.java b/server/src/com/vaadin/ui/declarative/Design.java index 59393a7815..dc96e789bf 100644 --- a/server/src/com/vaadin/ui/declarative/Design.java +++ b/server/src/com/vaadin/ui/declarative/Design.java @@ -184,13 +184,18 @@ public class Design implements Serializable { // taken care of by jsoup. Element root = doc.body(); Elements children = root.children(); - if (children.size() != 1) { + if (children.size() > 1) { throw new DesignException( - "The first level of a component hierarchy should contain exactly one root component, but found " - + children.size()); + "The first level of a component hierarchy should contain at most one root component, but found " + + children.size() + "."); } - Element element = children.first(); + Element element = children.size() == 0 ? null : children.first(); if (componentRoot != null) { + if (element == null) { + throw new DesignException( + "The root element cannot be null when the specified root Component is" + + " not null."); + } // user has specified root instance that may have member fields that // should be bound final FieldBinder binder; @@ -222,7 +227,8 @@ public class Design implements Serializable { designContext.removeComponentCreationListener(creationListener); } else { // createChild creates the entire component hierarchy - componentRoot = designContext.readDesign(element); + componentRoot = element == null ? null : designContext + .readDesign(element); } designContext.setRootComponent(componentRoot); return designContext; @@ -255,8 +261,10 @@ public class Design implements Serializable { // creates the entire component hierarchy rooted at the // given root node. Component root = designContext.getRootComponent(); - Node rootNode = designContext.createElement(root); - body.appendChild(rootNode); + if (root != null) { + Node rootNode = designContext.createElement(root); + body.appendChild(rootNode); + } designContext.writePackageMappings(doc); return doc; } @@ -424,10 +432,11 @@ public class Design implements Serializable { /** * Writes the given component tree in design format to the given output - * stream + * stream. * * @param component - * the root component of the component tree + * the root component of the component tree, null can be used for + * generating an empty design * @param outputStream * the output stream to write the design to. The design is always * written as UTF-8 @@ -446,8 +455,10 @@ public class Design implements Serializable { * and other information not available in the component tree. * * @param designContext - * the DesignContext object specifying the component hierarchy - * and the local id values of the objects + * The DesignContext object specifying the component hierarchy + * and the local id values of the objects. If + * designContext.getRootComponent() is null, an empty design will + * be generated. * @param outputStream * the output stream to write the design to. The design is always * written as UTF-8 diff --git a/server/src/com/vaadin/ui/declarative/DesignContext.java b/server/src/com/vaadin/ui/declarative/DesignContext.java index ade2494638..fd83339b76 100644 --- a/server/src/com/vaadin/ui/declarative/DesignContext.java +++ b/server/src/com/vaadin/ui/declarative/DesignContext.java @@ -415,7 +415,7 @@ public class DesignContext implements Serializable { * * @param componentDesign * The design element containing the description of the component - * to be created + * to be created. * @return the root component of component tree */ public Component readDesign(Element componentDesign) { diff --git a/server/tests/src/com/vaadin/tests/server/component/TestReadEmptyDesign.java b/server/tests/src/com/vaadin/tests/server/component/TestReadEmptyDesign.java new file mode 100644 index 0000000000..ecd303b678 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/TestReadEmptyDesign.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server.component; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import junit.framework.TestCase; + +import org.jsoup.nodes.Document; +import org.jsoup.nodes.DocumentType; +import org.jsoup.nodes.Element; + +import com.vaadin.ui.Component; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.declarative.Design; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.ui.declarative.DesignException; + +/** + * Test cases for checking that reading a design with no elements in the html + * body produces null as the root component. + */ +public class TestReadEmptyDesign extends TestCase { + InputStream is; + + @Override + protected void setUp() throws Exception { + super.setUp(); + String html = createDesign().toString(); + is = new ByteArrayInputStream(html.getBytes()); + } + + public void testReadComponent() { + Component root = Design.read(is); + assertNull("The root component should be null.", root); + } + + public void testReadContext() { + DesignContext ctx = Design.read(is, null); + assertNotNull("The design context should not be null.", ctx); + assertNull("The root component should be null.", ctx.getRootComponent()); + } + + public void testReadContextWithRootParameter() { + try { + Component rootComponent = new VerticalLayout(); + DesignContext ctx = Design.read(is, rootComponent); + fail("Reading a design with no elements should fail when a non-null root Component is specified."); + } catch (DesignException e) { + // This is the expected outcome, nothing to do. + } + } + + private Document createDesign() { + Document doc = new Document(""); + DocumentType docType = new DocumentType("html", "", "", ""); + doc.appendChild(docType); + Element html = doc.createElement("html"); + doc.appendChild(html); + html.appendChild(doc.createElement("head")); + html.appendChild(doc.createElement("body")); + return doc; + } +} \ No newline at end of file diff --git a/server/tests/src/com/vaadin/tests/server/component/TestWriteEmptyDesign.java b/server/tests/src/com/vaadin/tests/server/component/TestWriteEmptyDesign.java new file mode 100644 index 0000000000..b50915f1fd --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/TestWriteEmptyDesign.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server.component; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import junit.framework.TestCase; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; + +import com.vaadin.ui.Component; +import com.vaadin.ui.declarative.Design; +import com.vaadin.ui.declarative.DesignContext; + +/** + * Test cases for checking that writing a component hierarchy with null root + * produces an html document that has no elements in the html body. + */ +public class TestWriteEmptyDesign extends TestCase { + + public void testWriteComponent() throws IOException { + OutputStream os = new ByteArrayOutputStream(); + Design.write((Component) null, os); + checkHtml(os.toString()); + } + + public void testWriteContext() throws IOException { + OutputStream os = new ByteArrayOutputStream(); + DesignContext ctx = new DesignContext(); + ctx.setRootComponent(null); + Design.write(ctx, os); + checkHtml(os.toString()); + } + + private void checkHtml(String html) { + Document doc = Jsoup.parse(html); + Element body = doc.body(); + assertEquals("There should be no elements in the html body.", "", + body.html()); + } +} \ No newline at end of file -- 2.39.5