blob: 4d7608dac1ddc98499b6793d8bcfb99163835106 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.felix.scr.impl.inject.internal;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.felix.scr.impl.inject.internal.Annotations;
import org.mockito.Mockito;
import org.osgi.framework.Bundle;
import junit.framework.TestCase;
public class AnnotationTest extends TestCase
{
public void testMapIdentifierToKey() throws Exception
{
assertEquals("foo", Annotations.mapIdentifierToKey("foo"));
assertEquals("foo", Annotations.mapIdentifierToKey("$foo"));
assertEquals("foo", Annotations.mapIdentifierToKey("foo$"));
assertEquals("$foo", Annotations.mapIdentifierToKey("$$foo"));
assertEquals("foobar", Annotations.mapIdentifierToKey("foo$bar"));
assertEquals("foo$bar", Annotations.mapIdentifierToKey("foo$$bar"));
assertEquals("foo.", Annotations.mapIdentifierToKey("foo_"));
assertEquals("foo_", Annotations.mapIdentifierToKey("foo__"));
assertEquals(".foo", Annotations.mapIdentifierToKey("_foo"));
assertEquals("_foo", Annotations.mapIdentifierToKey("__foo"));
assertEquals("foo.bar", Annotations.mapIdentifierToKey("foo_bar"));
assertEquals("foo_bar", Annotations.mapIdentifierToKey("foo__bar"));
assertEquals("foo$", Annotations.mapIdentifierToKey("foo$$$"));
assertEquals("foo_.", Annotations.mapIdentifierToKey("foo___"));
assertEquals("foo-.bar", Annotations.mapIdentifierToKey("foo$_$_bar"));
assertEquals("six-prop", Annotations.mapIdentifierToKey("six$_$prop"));
assertEquals("seven$.prop", Annotations.mapIdentifierToKey("seven$$_$prop"));
}
public void testMapTypeNameToKey() throws Exception
{
assertEquals("service.ranking", Annotations.mapTypeNameToKey("ServiceRanking"));
assertEquals("some_value", Annotations.mapTypeNameToKey("Some_Value"));
assertEquals("osgi.property", Annotations.mapTypeNameToKey("OSGiProperty"));
}
public enum E1 {a, b, c}
public @interface A1 {
boolean bool();
byte byt();
char cha();
Class<?> clas();
E1 e1();
double doubl();
float floa();
int integer();
long lon();
short shor();
String string();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Bundle mockBundle() throws ClassNotFoundException
{
Bundle b = Mockito.mock(Bundle.class);
Mockito.when(b.loadClass(String.class.getName())).thenReturn((Class) String.class);
Mockito.when(b.loadClass(Integer.class.getName())).thenReturn((Class) Integer.class);
return b;
}
public void testA1() throws Exception
{
Map<String, Object> values = allValues();
Object o = Annotations.toObject( A1.class, values, mockBundle(), false);
assertTrue("expected an A1", o instanceof A1);
A1 a = (A1) o;
checkA1(a);
}
private void checkA1(A1 a)
{
assertEquals(true, a.bool());
assertEquals((byte)12, a.byt());
assertEquals('c', a.cha());
assertEquals(String.class, a.clas());
assertEquals(E1.a, a.e1());
assertEquals(3.14d, a.doubl());
assertEquals(500f, a.floa());
assertEquals(3, a.integer());
assertEquals(12345678l, a.lon());
assertEquals((short)3, a.shor());
assertEquals("3", a.string());
}
public void testA1FromArray() throws Exception
{
Map<String, Object> values = arrayValues();
Object o = Annotations.toObject( A1.class, values, mockBundle(), false);
assertTrue("expected an A1", o instanceof A1);
A1 a = (A1) o;
assertEquals(true, a.bool());
assertEquals((byte)12, a.byt());
assertEquals(String.class, a.clas());
assertEquals(E1.a, a.e1());
assertEquals(3.14d, a.doubl());
assertEquals(500f, a.floa());
assertEquals(3, a.integer());
assertEquals(12345678l, a.lon());
assertEquals((short)3, a.shor());
assertEquals(null, a.string());
}
private Map<String, Object> allValues()
{
Map<String, Object> values = new HashMap<>();
values.put("bool", "true");
values.put("byt", 12l);
values.put("cha", 'c');
values.put("clas", String.class.getName());
values.put("e1", E1.a.toString());
values.put("doubl", "3.14");
values.put("floa", 500l);
values.put("integer", 3.0d);
values.put("lon", "12345678");
values.put("shor", 3l);
values.put("string", 3);
values.put("array", new String[]{"foo", "bar"});
return values;
}
public void testA1NoValues() throws Exception
{
Map<String, Object> values = new HashMap<>();
Object o = Annotations.toObject( A1.class, values, mockBundle(), false);
assertTrue("expected an A1", o instanceof A1);
A1 a = (A1) o;
assertEquals(false, a.bool());
assertEquals((byte)0, a.byt());
assertEquals((char)0, a.cha());
assertEquals(null, a.clas());
assertEquals(null, a.e1());
assertEquals(0d, a.doubl());
assertEquals(0f, a.floa());
assertEquals(0, a.integer());
assertEquals(0l, a.lon());
assertEquals((short)0, a.shor());
assertEquals(null, a.string());
}
public @interface A2 {
boolean bool() default true;
byte byt() default 5;
char cha() default 'a';
Class<?> clas() default Integer.class;
E1 e1() default E1.b;
double doubl() default -2;
float floa() default -4;
int integer() default -5;
long lon() default Long.MIN_VALUE;
short shor() default -8;
String string() default "default";
String[] array() default {};
}
public void testA2AllValues() throws Exception
{
Map<String, Object> values = allValues();
Object o = Annotations.toObject( A2.class, values, mockBundle(), false);
assertTrue("expected an A2", o instanceof A2);
A2 a = (A2) o;
assertEquals(true, a.bool());
assertEquals((byte)12, a.byt());
assertEquals('c', a.cha());
assertEquals(String.class, a.clas());
assertEquals(E1.a, a.e1());
assertEquals(3.14d, a.doubl());
assertEquals(500f, a.floa());
assertEquals(3, a.integer());
assertEquals(12345678l, a.lon());
assertEquals((short)3, a.shor());
assertEquals("3", a.string());
assertArrayEquals(new String[]{"foo", "bar"}, a.array());
}
public void testA2DefaultValues() throws Exception
{
Map<String, Object> values = Collections.emptyMap();
Object o = Annotations.toObject( A2.class, values, mockBundle(), false);
assertTrue("expected an A2", o instanceof A2);
A2 a = (A2) o;
assertEquals(false, a.bool());
assertEquals((byte)0, a.byt());
assertEquals((char)0, a.cha());
assertEquals(null, a.clas());
assertEquals(null, a.e1());
assertEquals(0.0, a.doubl());
assertEquals(0.0f, a.floa());
assertEquals(0, a.integer());
assertEquals(0, a.lon());
assertEquals((short)0, a.shor());
assertEquals(null, a.string());
assertEquals(0, a.array().length);
}
public @interface A1Arrays {
boolean[] bool();
byte[] byt();
char[] cha();
Class<?>[] clas();
E1[] e1();
double[] doubl();
float[] floa();
int[] integer();
long[] lon();
short[] shor();
String[] string();
}
public void testA1ArraysNoValues() throws Exception
{
Map<String, Object> values = new HashMap<>();
Object o = Annotations.toObject( A1Arrays.class, values, mockBundle(), false);
assertTrue("expected an A1Arrays", o instanceof A1Arrays);
A1Arrays a = (A1Arrays) o;
assertEquals(0, a.bool().length);
assertEquals(0, a.byt().length);
assertEquals(0, a.cha().length);
assertEquals(0, a.clas().length);
assertEquals(0, a.e1().length);
assertEquals(0, a.doubl().length);
assertEquals(0, a.floa().length);
assertEquals(0, a.integer().length);
assertEquals(0, a.lon().length);
assertEquals(0, a.shor().length);
assertEquals(0, a.string().length);
}
public void testA1Array() throws Exception
{
Map<String, Object> values = allValues();
Object o = Annotations.toObject( A1Arrays.class, values, mockBundle(), false);
assertTrue("expected an A1Arrays", o instanceof A1Arrays);
A1Arrays a = (A1Arrays) o;
assertArrayEquals(new boolean[] {true}, a.bool());
assertArrayEquals(new byte[] {(byte)12}, a.byt());
assertArrayEquals(new char[] {'c'}, a.cha());
assertArrayEquals(new Class<?>[] {String.class}, a.clas());
assertArrayEquals(new E1[] {E1.a}, a.e1());
assertArrayEquals(new double[] {3.14d}, a.doubl());
assertArrayEquals(new float[] {500f}, a.floa());
assertArrayEquals(new int[] {3}, a.integer());
assertArrayEquals(new long[] {12345678l}, a.lon());
assertArrayEquals(new short[] {(short)3}, a.shor());
assertArrayEquals(new String[] {"3"}, a.string());
}
private void assertArrayEquals(Object a, Object b)
{
assertTrue(a.getClass().isArray());
assertTrue(b.getClass().isArray());
assertEquals("wrong length", Array.getLength(a), Array.getLength(b));
assertEquals("wrong type", a.getClass().getComponentType(), b.getClass().getComponentType());
for (int i = 0; i < Array.getLength(a); i++)
{
assertEquals("different value at " + i, Array.get(a, i), Array.get(b, i));
}
}
private Map<String, Object> arrayValues()
{
Map<String, Object> values = new HashMap<>();
values.put("bool", new boolean[] {true, false});
values.put("byt", new byte[] {12, 3});
values.put("cha", new char[] {'c', 'h', 'a', 'r'});
values.put("clas", new String[] {String.class.getName(), Integer.class.getName()});
values.put("e1", new String[] {E1.a.name(), E1.b.name()});
values.put("doubl", new double[] {3.14, 2.78, 9});
values.put("floa", new float[] {500, 37.44f});
values.put("integer", new int[] {3, 6, 9});
values.put("lon", new long[] {12345678l, -1});
values.put("shor", new short[] {3, 88});
values.put("string", new String[] {});
return values;
}
public void testA1ArrayFromArray() throws Exception
{
Map<String, Object> values = arrayValues();
doA1ArrayTest(values);
}
public void testA1ArrayFromCollection() throws Exception
{
Map<String, Object> values = arrayValues();
Map<String, Object> collectionValues = new HashMap<>();
for (Map.Entry<String, Object> entry: values.entrySet())
{
collectionValues.put(entry.getKey(), toList(entry.getValue()));
}
doA1ArrayTest(collectionValues);
}
private List<?> toList(Object value)
{
List<Object> result = new ArrayList<>();
for (int i = 0; i < Array.getLength(value); i++)
{
result.add(Array.get(value, i));
}
return result;
}
private void doA1ArrayTest(Map<String, Object> values) throws ClassNotFoundException
{
Object o = Annotations.toObject( A1Arrays.class, values, mockBundle(), false);
assertTrue("expected an A1Arrays", o instanceof A1Arrays);
A1Arrays a = (A1Arrays) o;
assertArrayEquals(new boolean[] {true, false}, a.bool());
assertArrayEquals(new byte[] {12, 3}, a.byt());
assertArrayEquals(new char[] {'c', 'h', 'a', 'r'}, a.cha());
assertArrayEquals(new Class<?>[] {String.class, Integer.class}, a.clas());
assertArrayEquals(new E1[] {E1.a, E1.b}, a.e1());
assertArrayEquals(new double[] {3.14, 2.78, 9}, a.doubl());
assertArrayEquals(new float[] {500f, 37.44f}, a.floa());
assertArrayEquals(new int[] {3, 6, 9}, a.integer());
assertArrayEquals(new long[] {12345678l, -1}, a.lon());
assertArrayEquals(new short[] {(short)3, 88}, a.shor());
assertArrayEquals(new String[] {}, a.string());
}
public @interface B1 {
boolean bool();
byte byt();
Class<?> clas();
E1 e1();
double doubl();
float floa();
int integer();
long lon();
short shor();
String string();
A1 a1();
A1[] a1array();
}
public void testB1() throws Exception
{
Map<String, Object> values = b1Values();
Object o = Annotations.toObject( B1.class, values, mockBundle(), true);
assertTrue("expected an B1 " + o, o instanceof B1);
B1 b = (B1) o;
checkB1(b);
}
private void checkB1(B1 b)
{
checkA1(b.a1());
assertEquals(3, b.a1array().length);
checkA1(b.a1array()[0]);
checkA1(b.a1array()[1]);
checkA1(b.a1array()[2]);
}
private Map<String, Object> b1Values()
{
Map<String, Object> a1Values = allValues();
Map<String, Object> values = allValues();
nest(values, "a1", 0, a1Values);
nest(values, "a1array", 0, a1Values);
nest(values, "a1array", 1, a1Values);
nest(values, "a1array", 2, a1Values);
return values;
}
private void nest(Map<String, Object> values, String key, int i,
Map<String, Object> a1Values)
{
for (Map.Entry<String, Object> entry: a1Values.entrySet())
{
values.put(key + "." + i + "." + entry.getKey(), entry.getValue());
}
}
public @interface C1 {
boolean bool();
byte byt();
Class<?> clas();
E1 e1();
double doubl();
float floa();
int integer();
long lon();
short shor();
String string();
B1 b1();
B1[] b1array();
}
public void testC1() throws Exception
{
Map<String, Object> values = c1Values();
Object o = Annotations.toObject( C1.class, values, mockBundle(), true);
assertTrue("expected an B1 " + o, o instanceof C1);
C1 c = (C1) o;
checkB1(c.b1());
assertEquals(3, c.b1array().length);
checkB1(c.b1array()[0]);
checkB1(c.b1array()[1]);
checkB1(c.b1array()[2]);
}
private Map<String, Object> c1Values()
{
Map<String, Object> b1Values = b1Values();
Map<String, Object> values = allValues();
nest(values, "b1", 0, b1Values);
nest(values, "b1array", 0, b1Values);
nest(values, "b1array", 1, b1Values);
nest(values, "b1array", 2, b1Values);
return values;
}
public interface I0 {
boolean bool();
byte byt();
Class<?> clas();
E1 e1();
}
public interface AI1 extends I0 {
double doubl();
float floa();
int integer();
long lon();
short shor();
String string();
}
public interface BI1 extends I0 {
double doubl();
float floa();
int integer();
long lon();
short shor();
String string();
AI1 a1();
AI1[] a1array();
}
public interface CI1 extends I0 {
double doubl();
float floa();
int integer();
long lon();
short shor();
String string();
BI1 b1();
BI1[] b1array();
}
public void testAI1() throws Exception
{
Map<String, Object> values = allValues();
Object o = Annotations.toObject( AI1.class, values, mockBundle(), true);
assertTrue("expected an AI1", o instanceof AI1);
AI1 a = (AI1) o;
checkAI1(a);
}
private void checkAI1(AI1 a)
{
assertEquals(true, a.bool());
assertEquals((byte)12, a.byt());
assertEquals(String.class, a.clas());
assertEquals(E1.a, a.e1());
assertEquals(3.14d, a.doubl());
assertEquals(500f, a.floa());
assertEquals(3, a.integer());
assertEquals(12345678l, a.lon());
assertEquals((short)3, a.shor());
assertEquals("3", a.string());
}
public void testBI1() throws Exception
{
Map<String, Object> values = b1Values();
Object o = Annotations.toObject( BI1.class, values, mockBundle(), true);
assertTrue("expected an B1 " + o, o instanceof BI1);
BI1 b = (BI1) o;
checkBI1(b);
}
private void checkBI1(BI1 b)
{
checkAI1(b.a1());
assertEquals(3, b.a1array().length);
checkAI1(b.a1array()[0]);
checkAI1(b.a1array()[1]);
checkAI1(b.a1array()[2]);
}
public void testCI1() throws Exception
{
Map<String, Object> values = c1Values();
Object o = Annotations.toObject( CI1.class, values, mockBundle(), true);
assertTrue("expected an B1 " + o, o instanceof CI1);
CI1 c = (CI1) o;
checkBI1(c.b1());
assertEquals(3, c.b1array().length);
checkBI1(c.b1array()[0]);
checkBI1(c.b1array()[1]);
checkBI1(c.b1array()[2]);
}
class Odd
{
private final String content;
public Odd(String content)
{
this.content = content;
}
public String getContent()
{
return content;
}
}
class Odder extends Odd
{
public Odder(String content)
{
super(content);
}
}
interface OddTest
{
Odd odd1();
Odd odd2();
Odd odd3();
Odd odder1();
Odd odder2();
Odd odder3();
}
public void testOddClasses() throws Exception
{
Map<String, Object> values = new HashMap<>();
values.put("odd1", new Odd("one"));
values.put("odd2", Collections.singletonList(new Odd("two")));
values.put("odd3", new Odd[] {new Odd("three"), new Odd("four")});
values.put("odder1", new Odder("one"));
values.put("odder2", Collections.singletonList(new Odder("two")));
values.put("odder3", new Odder[] {new Odder("three"), new Odder("four")});
Object o = Annotations.toObject(OddTest.class, values, mockBundle(), true);
assertTrue("expected an OddTest", o instanceof OddTest);
OddTest ot = (OddTest)o;
assertOdd("one", ot.odd1());
assertOdd("two", ot.odd2());
assertOdd("three", ot.odd3());
assertOdder("one", ot.odder1());
assertOdder("two", ot.odder2());
assertOdder("three", ot.odder3());
}
public @interface SETest1 {
String value();
}
public @interface SETest2 {
boolean foo() default true;
String value();
}
public @interface SETest3 {
boolean foo();
String value();
}
public @interface SETest4 {
boolean foo();
String values();
}
public @interface PrefixTest {
String PREFIX_ = "org.apache.";
boolean foo() default true;
String[] values() default {"a"};
String value();
}
public @interface SingleElementTest {
String PREFIX_ = "org.apache.";
String value();
}
public void testSingleElementAnnotation() throws Exception
{
assertFalse(Annotations.isSingleElementAnnotation(Map.class));
assertTrue(Annotations.isSingleElementAnnotation(SETest1.class));
assertTrue(Annotations.isSingleElementAnnotation(SETest2.class));
assertFalse(Annotations.isSingleElementAnnotation(SETest3.class));
assertFalse(Annotations.isSingleElementAnnotation(SETest4.class));
assertTrue(Annotations.isSingleElementAnnotation(SingleElementTest.class));
}
public void testGetPrefix() throws Exception
{
assertNull(Annotations.getPrefix(Map.class));
assertNull(Annotations.getPrefix(SETest1.class));
assertNull(Annotations.getPrefix(SETest2.class));
assertNull(Annotations.getPrefix(SETest3.class));
assertNull(Annotations.getPrefix(SETest4.class));
assertNull(Annotations.getPrefix(A1.class));
assertEquals("org.apache.", Annotations.getPrefix(PrefixTest.class));
}
public void testMappingWithPrefix() throws Exception
{
final Map<String, Object> values = new HashMap<>();
values.put("foo", false);
values.put("org.apache.foo", true);
values.put("values", "false-values");
values.put("org.apache.values", "true-values");
values.put("value", "false-value");
values.put("org.apache.prefix.test", "true-value");
final PrefixTest o = Annotations.toObject( PrefixTest.class, values, mockBundle(), true);
assertEquals("true-value", o.value());
assertEquals(1, o.values().length);
assertEquals("true-values", o.values()[0]);
assertEquals(true, o.foo());
}
public void testMappingWithPrefixSingleValue() throws Exception
{
final Map<String, Object> values = new HashMap<>();
values.put("value", "false-value");
values.put("org.apache.single.element.test", "true-value");
final SingleElementTest o = Annotations.toObject( SingleElementTest.class, values, mockBundle(), true);
assertEquals("true-value", o.value());
}
private void assertOdd(String expectedContent, Object actual) {
assertTrue("expected an Odd", actual instanceof Odd);
assertEquals("Expected Odd contents", expectedContent, ((Odd)actual).getContent());
}
private void assertOdder(String expectedContent, Object actual) {
assertTrue("expected an Odder", actual instanceof Odder);
assertEquals("Expected Odd contents", expectedContent, ((Odder)actual).getContent());
}
}