View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.annotation;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.junit.bct.BctAssertions.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import org.apache.juneau.*;
24  import org.apache.juneau.commons.reflect.ExecutableException;
25  import org.junit.jupiter.api.*;
26  
27  class NamePropertyAnnotation_Test extends TestBase {
28  
29  	private static final String CNAME = NamePropertyAnnotation_Test.class.getName();
30  
31  	//------------------------------------------------------------------------------------------------------------------
32  	// Basic tests
33  	//------------------------------------------------------------------------------------------------------------------
34  
35  	NameProperty a1 = NamePropertyAnnotation.create()
36  		.description("a")
37  		.on("b")
38  		.build();
39  
40  	NameProperty a2 = NamePropertyAnnotation.create()
41  		.description("a")
42  		.on("b")
43  		.build();
44  
45  	@Test void a01_basic() {
46  		assertBean(a1, "description,on", "[a],[b]");
47  	}
48  
49  	@Test void a02_testEquivalency() {
50  		assertEquals(a2, a1);
51  		assertNotEqualsAny(a1.hashCode(), 0, -1);
52  		assertEquals(a1.hashCode(), a2.hashCode());
53  	}
54  
55  	//------------------------------------------------------------------------------------------------------------------
56  	// PropertyStore equivalency.
57  	//------------------------------------------------------------------------------------------------------------------
58  
59  	@Test void b01_testEquivalencyInPropertyStores() {
60  		var bc1 = BeanContext.create().annotations(a1).build();
61  		var bc2 = BeanContext.create().annotations(a2).build();
62  		assertSame(bc1, bc2);
63  	}
64  
65  	//------------------------------------------------------------------------------------------------------------------
66  	// Other methods.
67  	//------------------------------------------------------------------------------------------------------------------
68  
69  	public static class C1 {
70  		public int f1;
71  		public void m1() {}  // NOSONAR
72  	}
73  	public static class C2 {
74  		public int f2;
75  		public void m2() {}  // NOSONAR
76  	}
77  
78  	@Test void c01_otherMethods() throws Exception {
79  		var c1 = NamePropertyAnnotation.create("a").on("b").build();
80  		var c2 = NamePropertyAnnotation.create().on(C1.class.getField("f1")).on(C2.class.getField("f2")).build();
81  		var c3 = NamePropertyAnnotation.create().on(C1.class.getMethod("m1")).on(C2.class.getMethod("m2")).build();
82  
83  		assertBean(c1, "on", "[a,b]");
84  		assertBean(c2, "on", "["+CNAME+"$C1.f1,"+CNAME+"$C2.f2]");
85  		assertBean(c3, "on", "["+CNAME+"$C1.m1(),"+CNAME+"$C2.m2()]");
86  	}
87  
88  	//------------------------------------------------------------------------------------------------------------------
89  	// Comparison with declared annotations.
90  	//------------------------------------------------------------------------------------------------------------------
91  
92  	@NameProperty(
93  		description={ "a" },
94  		on="b"
95  	)
96  	public static class D1 {}
97  	NameProperty d1 = D1.class.getAnnotationsByType(NameProperty.class)[0];
98  
99  	@NameProperty(
100 		description={ "a" },
101 		on="b"
102 	)
103 	public static class D2 {}
104 	NameProperty d2 = D2.class.getAnnotationsByType(NameProperty.class)[0];
105 
106 	@Test void d01_comparisonWithDeclarativeAnnotations() {
107 		assertEqualsAll(a1, d1, d2);
108 		assertNotEqualsAny(a1.hashCode(), 0, -1);
109 		assertEqualsAll(a1.hashCode(), d1.hashCode(), d2.hashCode());
110 	}
111 
112 	//------------------------------------------------------------------------------------------------------------------
113 	// Property functionality tests.
114 	//------------------------------------------------------------------------------------------------------------------
115 
116 	public static class TestBeanWithNamePropertyField {
117 		@NameProperty
118 		public String name;
119 	}
120 
121 	public static class TestBeanWithNamePropertyMethod {
122 		private String name;
123 
124 		@NameProperty
125 		protected void setName(String name) {
126 			this.name = name;
127 		}
128 
129 		public String getName() {
130 			return name;
131 		}
132 	}
133 
134 	@Test void e01_namePropertyField() throws Exception {
135 		var bc = BeanContext.DEFAULT;
136 		var cm = bc.getClassMeta(TestBeanWithNamePropertyField.class);
137 		var prop = cm.getNameProperty();
138 		assertNotNull(prop, "NameProperty should be found");
139 		assertTrue(prop.canWrite(), "Should have setter");
140 		assertTrue(prop.canRead(), "Should have getter");
141 
142 		var bean = new TestBeanWithNamePropertyField();
143 		prop.set(bean, "testName");
144 		assertEquals("testName", prop.get(bean));
145 		assertEquals("testName", bean.name);
146 	}
147 
148 	@Test void e02_namePropertyMethod() throws Exception {
149 		var bc = BeanContext.DEFAULT;
150 		var cm = bc.getClassMeta(TestBeanWithNamePropertyMethod.class);
151 		var prop = cm.getNameProperty();
152 		assertNotNull(prop, "NameProperty should be found");
153 		assertTrue(prop.canWrite(), "Should have setter");
154 		assertTrue(prop.canRead(), "Should have getter");
155 
156 		var bean = new TestBeanWithNamePropertyMethod();
157 		prop.set(bean, "testName");
158 		assertEquals("testName", prop.get(bean));
159 		assertEquals("testName", bean.getName());
160 	}
161 
162 	@Test void e03_namePropertyNotFound() {
163 		var bc = BeanContext.DEFAULT;
164 		var cm = bc.getClassMeta(String.class);
165 		var prop = cm.getNameProperty();
166 		assertNull(prop, "NameProperty should not be found on String class");
167 	}
168 
169 	public static class TestBeanWithNamePropertyIntegerField {
170 		@NameProperty
171 		public Integer id;
172 	}
173 
174 	public static class TestBeanWithNamePropertyIntegerMethod {
175 		private Integer id;
176 
177 		@NameProperty
178 		protected void setId(Integer id) {
179 			this.id = id;
180 		}
181 
182 		public Integer getId() {
183 			return id;
184 		}
185 	}
186 
187 	@Test void e04_namePropertyWithIntegerField() throws Exception {
188 		var bc = BeanContext.DEFAULT;
189 		var cm = bc.getClassMeta(TestBeanWithNamePropertyIntegerField.class);
190 		var prop = cm.getNameProperty();
191 		assertNotNull(prop, "NameProperty should be found");
192 		assertTrue(prop.canWrite(), "Should have setter");
193 		assertTrue(prop.canRead(), "Should have getter");
194 
195 		var bean = new TestBeanWithNamePropertyIntegerField();
196 		prop.set(bean, 42);
197 		assertEquals(42, prop.get(bean));
198 		assertEquals(Integer.valueOf(42), bean.id);
199 	}
200 
201 	@Test void e05_namePropertyWithIntegerMethod() throws Exception {
202 		var bc = BeanContext.DEFAULT;
203 		var cm = bc.getClassMeta(TestBeanWithNamePropertyIntegerMethod.class);
204 		var prop = cm.getNameProperty();
205 		assertNotNull(prop, "NameProperty should be found");
206 		assertTrue(prop.canWrite(), "Should have setter");
207 		assertTrue(prop.canRead(), "Should have getter");
208 
209 		var bean = new TestBeanWithNamePropertyIntegerMethod();
210 		prop.set(bean, 42);
211 		assertEquals(42, prop.get(bean));
212 		assertEquals(Integer.valueOf(42), bean.getId());
213 	}
214 
215 	public static class TestBeanWithReadOnlyNameProperty {
216 		private String name = "defaultName";
217 
218 		@NameProperty
219 		public String getName() {
220 			return name;
221 		}
222 	}
223 
224 	@Test void e06_readOnlyNameProperty() throws Exception {
225 		var bc = BeanContext.DEFAULT;
226 		var cm = bc.getClassMeta(TestBeanWithReadOnlyNameProperty.class);
227 		var prop = cm.getNameProperty();
228 		assertNotNull(prop, "NameProperty should be found even if read-only");
229 		assertFalse(prop.canWrite(), "Should not have setter");
230 		assertTrue(prop.canRead(), "Should have getter");
231 
232 		var bean = new TestBeanWithReadOnlyNameProperty();
233 		assertEquals("defaultName", prop.get(bean));
234 
235 		// Verify that set() throws an exception
236 		var ex = assertThrows(ExecutableException.class, () -> prop.set(bean, "newName"));
237 		assertTrue(ex.getMessage().contains("No setter defined"), "Should throw exception when trying to set read-only property");
238 	}
239 }