aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Anisimov <denis@vaadin.com>2014-11-22 12:27:01 +0200
committerVaadin Code Review <review@vaadin.com>2016-02-29 13:11:16 +0000
commit89f76b9dbad93260632ae1e025b607daa64d9f81 (patch)
tree565b39d3080cf219ada68cfcf6c49f2d8d89f8d6
parent4ee39c397a85618e65d2e5dcd3ec556569a73719 (diff)
downloadvaadin-framework-89f76b9dbad93260632ae1e025b607daa64d9f81.tar.gz
vaadin-framework-89f76b9dbad93260632ae1e025b607daa64d9f81.zip
Use @Inherited for annotations that have inherited semantic (#12351).
Change-Id: I70f0d79095bfd05b83905df6a3eedd1a5e93b48e
-rw-r--r--WebContent/release-notes.html2
-rw-r--r--server/src/com/vaadin/annotations/PreserveOnRefresh.java2
-rw-r--r--server/src/com/vaadin/annotations/Push.java2
-rw-r--r--server/src/com/vaadin/annotations/Theme.java2
-rw-r--r--server/src/com/vaadin/annotations/Title.java2
-rw-r--r--server/src/com/vaadin/annotations/VaadinServletConfiguration.java2
-rw-r--r--server/src/com/vaadin/annotations/Widgetset.java2
-rw-r--r--server/src/com/vaadin/server/UIProvider.java34
-rw-r--r--server/tests/src/com/vaadin/server/UIProviderTest.java113
9 files changed, 152 insertions, 9 deletions
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index 4286b3ace0..f7b5611be5 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -140,6 +140,8 @@
cause problems with external libraries compiled against said versions.</li>
<li>Declarative format is now using "vaadin-" as a default prefix instead of the "v-" prefix used in 7.5.
This default can be changed in deployment configuration.</li>
+ <li>The annotations @PreserveOnRefresh, @Push, @Theme, @Title, @VaadinServletConfiguration and @Widgetset now use
+ @Inherited. The annotation is also looked up in extended interfaces for backwards compatibility.</li>
</ul>
<h3 id="knownissues">Known Issues and Limitations</h3>
<ul>
diff --git a/server/src/com/vaadin/annotations/PreserveOnRefresh.java b/server/src/com/vaadin/annotations/PreserveOnRefresh.java
index 7f4ef3ffe5..86723b97fc 100644
--- a/server/src/com/vaadin/annotations/PreserveOnRefresh.java
+++ b/server/src/com/vaadin/annotations/PreserveOnRefresh.java
@@ -17,6 +17,7 @@
package com.vaadin.annotations;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -45,6 +46,7 @@ import com.vaadin.ui.UI;
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
+@Inherited
public @interface PreserveOnRefresh {
// Empty marker annotation
}
diff --git a/server/src/com/vaadin/annotations/Push.java b/server/src/com/vaadin/annotations/Push.java
index b6a28c1560..736bc4488b 100644
--- a/server/src/com/vaadin/annotations/Push.java
+++ b/server/src/com/vaadin/annotations/Push.java
@@ -17,6 +17,7 @@
package com.vaadin.annotations;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -38,6 +39,7 @@ import com.vaadin.ui.UI;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
+@Inherited
public @interface Push {
/**
* Returns the {@link PushMode} to use for the annotated UI. The default
diff --git a/server/src/com/vaadin/annotations/Theme.java b/server/src/com/vaadin/annotations/Theme.java
index 61c47389ad..03fa1179bc 100644
--- a/server/src/com/vaadin/annotations/Theme.java
+++ b/server/src/com/vaadin/annotations/Theme.java
@@ -17,6 +17,7 @@
package com.vaadin.annotations;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -28,6 +29,7 @@ import com.vaadin.ui.UI;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
+@Inherited
public @interface Theme {
/**
* @return simple name of the theme
diff --git a/server/src/com/vaadin/annotations/Title.java b/server/src/com/vaadin/annotations/Title.java
index 38a3d75f17..07eaf17e33 100644
--- a/server/src/com/vaadin/annotations/Title.java
+++ b/server/src/com/vaadin/annotations/Title.java
@@ -17,6 +17,7 @@
package com.vaadin.annotations;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -28,6 +29,7 @@ import com.vaadin.ui.UI;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
+@Inherited
public @interface Title {
/**
* Gets the HTML title that should be used if the UI is used on it's own.
diff --git a/server/src/com/vaadin/annotations/VaadinServletConfiguration.java b/server/src/com/vaadin/annotations/VaadinServletConfiguration.java
index 00af38ecc1..907f2c3a0c 100644
--- a/server/src/com/vaadin/annotations/VaadinServletConfiguration.java
+++ b/server/src/com/vaadin/annotations/VaadinServletConfiguration.java
@@ -18,6 +18,7 @@ package com.vaadin.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -44,6 +45,7 @@ import com.vaadin.ui.UI;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
+@Inherited
public @interface VaadinServletConfiguration {
/**
* Defines the init parameter name for methods in
diff --git a/server/src/com/vaadin/annotations/Widgetset.java b/server/src/com/vaadin/annotations/Widgetset.java
index c6ef6a7194..2dcf93af13 100644
--- a/server/src/com/vaadin/annotations/Widgetset.java
+++ b/server/src/com/vaadin/annotations/Widgetset.java
@@ -17,6 +17,7 @@
package com.vaadin.annotations;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -28,6 +29,7 @@ import com.vaadin.ui.UI;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
+@Inherited
public @interface Widgetset {
/**
* @return name of the widgetset
diff --git a/server/src/com/vaadin/server/UIProvider.java b/server/src/com/vaadin/server/UIProvider.java
index d3d834cad7..4ed86b9c31 100644
--- a/server/src/com/vaadin/server/UIProvider.java
+++ b/server/src/com/vaadin/server/UIProvider.java
@@ -18,6 +18,7 @@ package com.vaadin.server;
import java.io.Serializable;
import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.annotations.Push;
@@ -43,8 +44,15 @@ public abstract class UIProvider implements Serializable {
/**
* Helper to get an annotation for a class. If the annotation is not present
- * on the target class, its super classes and implemented interfaces are
- * also searched for the annotation.
+ * on the target class, its super classes and directly implemented
+ * interfaces are also searched for the annotation. Interfaces implemented
+ * by superclasses are not taken into account.
+ * <p>
+ * Note that searching implemented interfaces for {@code @Inherited}
+ * annotations and searching for superclasses for non-inherited annotations
+ * do not follow the standard semantics and are supported for backwards
+ * compatibility. Future versions of the framework might only support the
+ * standard semantics of {@code @Inherited}.
*
* @param clazz
* the class from which the annotation should be found
@@ -55,18 +63,26 @@ public abstract class UIProvider implements Serializable {
*/
protected static <T extends Annotation> T getAnnotationFor(Class<?> clazz,
Class<T> annotationType) {
- // Find from the class hierarchy
- Class<?> currentType = clazz;
- while (currentType != Object.class) {
- T annotation = currentType.getAnnotation(annotationType);
+ // Don't discover hierarchy if annotation is inherited
+ if (annotationType.getAnnotation(Inherited.class) != null) {
+ T annotation = clazz.getAnnotation(annotationType);
if (annotation != null) {
return annotation;
- } else {
- currentType = currentType.getSuperclass();
+ }
+ } else {
+ // Find from the class hierarchy
+ Class<?> currentType = clazz;
+ while (currentType != Object.class) {
+ T annotation = currentType.getAnnotation(annotationType);
+ if (annotation != null) {
+ return annotation;
+ } else {
+ currentType = currentType.getSuperclass();
+ }
}
}
- // Find from an implemented interface
+ // Find from a directly implemented interface
for (Class<?> iface : clazz.getInterfaces()) {
T annotation = iface.getAnnotation(annotationType);
if (annotation != null) {
diff --git a/server/tests/src/com/vaadin/server/UIProviderTest.java b/server/tests/src/com/vaadin/server/UIProviderTest.java
new file mode 100644
index 0000000000..579a3f1858
--- /dev/null
+++ b/server/tests/src/com/vaadin/server/UIProviderTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.server;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.annotations.Widgetset;
+
+/**
+ * Tests for {@link UIProvider} class.
+ *
+ * @author Vaadin Ltd
+ */
+public class UIProviderTest {
+
+ @Test
+ public void getAnnotationFor_widgetsetAnnotationForSubclass_annotationFound() {
+ Assert.assertNotNull("Widgetset annotation is not found for subclass",
+ UIProvider.getAnnotationFor(TestClass.class, Widgetset.class));
+ }
+
+ @Test
+ public void getAnnotationFor_themeAnnotationForSubclass_annotationFound() {
+ Assert.assertNotNull("Theme annotation is not found for subclass",
+ UIProvider.getAnnotationFor(TestClass.class, Theme.class));
+ }
+
+ @Test
+ public void getAnnotationFor_themeAnnotationForSubclass_annotationOverridden() {
+ Assert.assertEquals(
+ "Theme annotation is not overridden correctly in subclass",
+ "c", UIProvider.getAnnotationFor(TestClass.class, Theme.class)
+ .value());
+ }
+
+ @Test
+ public void getAnnotationFor_notInheritedAnnotationForSubclass_annotationFound() {
+ Assert.assertNotNull(
+ "TestAnnotation annotation is not found for subclass",
+ UIProvider.getAnnotationFor(TestClass.class,
+ TestAnnotation.class));
+ }
+
+ @Test
+ public void getAnnotationFor_directAnnotationForSubclass_annotationFound() {
+ Assert.assertNotNull(
+ "TestAnnotation1 annotation is not found for subclass",
+ UIProvider.getAnnotationFor(TestClass.class,
+ TestAnnotation1.class));
+ }
+
+ @Test
+ public void getAnnotationFor_annotationInheritedFromInterface_annotationFound() {
+ Assert.assertNotNull(
+ "Theme annotation is not inherited from interface", UIProvider
+ .getAnnotationFor(ClassImplementingInterface.class,
+ Theme.class));
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface TestAnnotation {
+
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface TestAnnotation1 {
+
+ }
+
+ @Widgetset("a")
+ @Theme("b")
+ @TestAnnotation
+ public static class TestSuperClass {
+
+ }
+
+ @TestAnnotation1
+ @Theme("c")
+ public static class TestClass extends TestSuperClass {
+
+ }
+
+ @Theme("d")
+ public interface InterfaceWithAnnotation {
+ }
+
+ public static class ClassImplementingInterface implements
+ InterfaceWithAnnotation {
+ }
+
+}