package org.mongodb.morphia.utils;
import org.junit.Test;
import org.mongodb.morphia.TestBase;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Field;
import org.mongodb.morphia.annotations.Id;
import org.mongodb.morphia.annotations.Index;
import org.mongodb.morphia.annotations.Indexes;
import org.mongodb.morphia.mapping.Mapper;
import java.io.Serializable;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.CoreMatchers.isA;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mongodb.morphia.testutil.ExactClassMatcher.exactClass;
/**
* @author Uwe Schaefer, (us@thomas-daily.de)
* @author Scott Hernandez
*/
@SuppressWarnings("UnusedDeclaration")
public class ReflectionUtilsTest extends TestBase {
@Test
public void shouldAcceptMapWithoutItsOwnGenericParameters() {
Class parameterizedClass = ReflectionUtils.getParameterizedClass(MapWithoutGenericTypes.class);
assertThat(parameterizedClass, is(exactClass(Integer.class)));
}
@Test
public void shouldSupportGenericArrays() {
getMorphia().map(MyEntity.class);
}
/**
* Tests that in a class hierarchy of arbitrary depth, we can get the correct declared field type
*
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void testGenericFieldTypeResolution() throws Exception {
Class<?> typeArgument = ReflectionUtils.getTypeArgument(Sub.class,
(TypeVariable) Super1.class.getDeclaredField("field").getGenericType());
assertThat(typeArgument, is(exactClass(Integer.class)));
}
@Test
public void testGetFromJarFileOnlyLoadsClassesInSpecifiedPackage() throws Exception {
//we need a jar to test with so use JUnit since it will always be there
String rootPath = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
Set<Class<?>> result = ReflectionUtils.getFromJARFile(Thread.currentThread().getContextClassLoader(), rootPath, "org/junit", true);
for (Class clazz : result) {
assertThat(clazz.getPackage().getName().startsWith("org.junit"), is(true));
}
assertThat(result.contains(org.junit.Assert.class), is(true));
assertThat(result.contains(org.junit.rules.RuleChain.class), is(true));
}
@Test
public void testGetParameterizedClassInheritance() throws Exception {
// Work before fix...
assertThat(ReflectionUtils.getParameterizedClass(Set.class), isA(Object.class));
assertThat(ReflectionUtils.getParameterizedClass(Book.class.getDeclaredField("authorsSet")), is(exactClass(Author.class)));
// Works now...
assertThat(ReflectionUtils.getParameterizedClass(Book.class.getDeclaredField("authors")), is(exactClass(Author.class)));
assertThat(ReflectionUtils.getParameterizedClass(Authors.class), is(exactClass(Author.class)));
assertThat(ReflectionUtils.getParameterizedClass(WritingTeam.class), is(is(exactClass(Author.class))));
}
/**
* Test method for {@link ReflectionUtils#implementsInterface(Class, Class)} .
*/
@Test
public void testImplementsInterface() {
assertThat(ReflectionUtils.implementsInterface(ArrayList.class, List.class), is(true));
assertThat(ReflectionUtils.implementsInterface(ArrayList.class, Collection.class), is(true));
assertThat(ReflectionUtils.implementsInterface(ArrayList.class, Collection.class), is(true));
assertThat(ReflectionUtils.implementsInterface(Set.class, List.class), is(false));
assertThat(ReflectionUtils.implementsInterface(List.class, ArrayList.class), is(false));
}
@Test
public void testInheritedClassAnnotations() {
final List<Indexes> annotations = ReflectionUtils.getAnnotations(Foobie.class, Indexes.class);
assertThat(annotations.size(), is(2));
assertThat(ReflectionUtils.getAnnotation(Foobie.class, Indexes.class) != null, is(true));
assertThat("Base".equals(ReflectionUtils.getClassEntityAnnotation(Foo.class).value()), is(true));
assertThat("Sub".equals(ReflectionUtils.getClassEntityAnnotation(Foobie.class).value()), is(true));
assertThat(ReflectionUtils.getClassEntityAnnotation(Fooble.class).value(), is(Mapper.IGNORED_FIELDNAME));
}
private interface MapWithoutGenericTypes extends Map<Integer, String> {
}
@Entity("generic_arrays")
static class MyEntity {
@Id
private String id;
private Integer[] integers;
private Super3<Integer>[] super3s;
}
@Entity("Base")
@Indexes(@Index(fields = @Field("id")))
private static class Foo {
@Id
private int id;
}
@Entity("Sub")
@Indexes(@Index(fields = @Field("test")))
private static class Foobie extends Foo {
private String test;
}
@Entity
private static class Fooble extends Foobie {
}
private static class Author {
}
private static class Authors extends HashSet<Author> {
// Can contain utils methods
}
private static class WritingTeam extends Authors {
}
private static class Book {
private Authors authors;
private Set<Author> authorsSet;
}
private static class Super1<T extends Object> {
private T field;
}
private static class Super2<T extends Serializable> extends Super1<T> {
}
private static class Super3<T extends Number> extends Super2<T> {
}
private static class Sub extends Super3<Integer> {
}
}