/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.test.internal.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.Date;
import org.hibernate.validator.internal.util.ExecutableHelper;
import org.hibernate.validator.internal.util.TypeResolutionHelper;
import org.hibernate.validator.test.internal.util.classhierarchy.Novella;
import org.hibernate.validator.testutil.TestForIssue;
import org.testng.annotations.Test;
/**
* Unit test for {@link ExecutableHelper}.
*
* @author Gunnar Morling
*/
public class ExecutableHelperTest {
private final ExecutableHelper executableHelper = new ExecutableHelper( new TypeResolutionHelper() );
@Test
@TestForIssue(jiraKey = "HV-818")
public void testOverrides() throws Exception {
Method getBar = Qax.class.getMethod( "getBar" );
Method getBarString = Qax.class.getMethod( "getBar", String.class );
Method getSubTypeBar = SubQax.class.getMethod( "getBar" );
Method getSubTypeBarString = SubQax.class.getMethod( "getBar", String.class );
Method getBarInteger = SubQax.class.getMethod( "getBar", Integer.class );
Method getFooLong = SubQax.class.getMethod( "getFoo", Long.class );
Method getStaticFoo = SubQax.class.getMethod( "getFoo" );
Method getStaticFooString = SubQax.class.getMethod( "getFoo", String.class );
Method getStaticFooInteger = SubQax.class.getMethod( "getFoo", Integer.class );
Method getSuperTypeStaticFoo = Qax.class.getMethod( "getFoo" );
assertTrue( executableHelper.overrides( getSubTypeBar, getBar ) );
assertTrue( executableHelper.overrides( getSubTypeBarString, getBarString ) );
assertFalse( executableHelper.overrides( getBar, getBarString ) );
assertFalse( executableHelper.overrides( getBar, getBarInteger ) );
assertFalse( executableHelper.overrides( getBarString, getBarInteger ) );
assertFalse( executableHelper.overrides( getSubTypeBar, getBarInteger ) );
assertFalse( executableHelper.overrides( getSubTypeBar, getBarString ) );
assertFalse( executableHelper.overrides( getSubTypeBarString, getBarInteger ) );
assertFalse( executableHelper.overrides( getSubTypeBarString, getBar ) );
assertFalse( executableHelper.overrides( getSubTypeBarString, getSubTypeBar ) );
assertFalse( executableHelper.overrides( getStaticFoo, getStaticFooString ) );
assertFalse( executableHelper.overrides( getStaticFoo, getStaticFooInteger ) );
assertFalse( executableHelper.overrides( getStaticFooString, getStaticFooInteger ) );
assertFalse( executableHelper.overrides( getFooLong, getStaticFoo ) );
assertFalse( executableHelper.overrides( getFooLong, getStaticFooInteger ) );
assertFalse( executableHelper.overrides( getFooLong, getStaticFooString ) );
assertFalse( executableHelper.overrides( getStaticFoo, getSuperTypeStaticFoo ) );
}
@Test
public void methodFromSubTypeOverridesSuperTypeMethod() throws Exception {
Method methodFromBase = Foo.class.getDeclaredMethod( "zap" );
Method methodFromImpl = Bar.class.getDeclaredMethod( "zap" );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
}
@Test
public void methodFromSubTypeOverridesInterfaceTypeMethod() throws Exception {
Method methodFromBase = IBaz.class.getDeclaredMethod( "zap" );
Method methodFromImpl = Baz.class.getDeclaredMethod( "zap" );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
}
@Test
public void methodFromSuperTypeDoesNotOverrideSubTypeMethod() throws Exception {
Method methodFromBase = Foo.class.getDeclaredMethod( "zap" );
Method methodFromImpl = Bar.class.getDeclaredMethod( "zap" );
assertThat( executableHelper.overrides( methodFromBase, methodFromImpl ) ).isFalse();
}
@Test
public void methodWithDifferentNameDoesNotOverride() throws Exception {
Method methodFromBase = Foo.class.getDeclaredMethod( "zap" );
Method methodFromImpl = Bar.class.getDeclaredMethod( "zip" );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithDifferentParameterTypesDoesNotOverride() throws Exception {
Method methodFromBase = Foo.class.getDeclaredMethod( "zap" );
Method methodFromImpl = Bar.class.getDeclaredMethod( "zap", int.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodDefinedInOtherTypeHierarchyDoesNotOverride() throws Exception {
Method first = Foo.class.getDeclaredMethod( "zap" );
Method other = Baz.class.getDeclaredMethod( "zap" );
assertThat( executableHelper.overrides( other, first ) ).isFalse();
}
@Test
public void methodWithNarrowedParameterTypeDoesNotOverride() throws Exception {
Method methodFromBase = SimpleServiceBase.class.getDeclaredMethods()[0];
Method methodFromImpl = SimpleServiceImpl1.class.getDeclaredMethod( "doSomething", Number.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = SimpleServiceImpl1.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithIntermediateClass() throws Exception {
Method methodFromBase = SimpleServiceBase.class.getDeclaredMethods()[0];
Method methodFromImpl = SimpleServiceImpl2.class.getDeclaredMethod( "doSomething", Number.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = SimpleServiceImpl2.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithGenerics() throws Exception {
Method methodFromBase = GenericServiceBase.class.getDeclaredMethods()[0];
Method methodFromImpl = GenericServiceImpl1.class.getDeclaredMethod( "doSomething", Number.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = GenericServiceImpl1.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithGenericsAndIntermediateClass() throws Exception {
Method methodFromBase = GenericServiceBase.class.getDeclaredMethods()[0];
Method methodFromImpl = GenericServiceImpl2.class.getDeclaredMethod( "doSomething", Number.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = GenericServiceImpl2.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithGenericsAndMultipleIntermediateClasses() throws Exception {
Method methodFromBase = GenericServiceBase.class.getDeclaredMethods()[0];
Method methodFromImpl = GenericServiceImpl3.class.getDeclaredMethod( "doSomething", Number.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = GenericServiceImpl2.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithParameterizedSubType() throws Exception {
Method methodFromBase = GenericServiceBase.class.getDeclaredMethods()[0];
Method methodFromImpl = ParameterizedSubType.class.getDeclaredMethod( "doSomething", Object.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = ParameterizedSubType.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithGenericInterface() throws Exception {
Method methodFromBase = GenericInterface.class.getDeclaredMethods()[0];
Method methodFromImpl = GenericInterfaceImpl1.class.getDeclaredMethod( "doSomething", Number.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = GenericInterfaceImpl1.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void methodWithWildcard() throws Exception {
Method methodFromBase = WildcardInterface.class.getDeclaredMethods()[0];
Method methodFromImpl = WildcardInterfaceImpl.class.getDeclaredMethod( "doSomething", Integer.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isTrue();
methodFromImpl = WildcardInterfaceImpl.class.getDeclaredMethod( "doSomething", Long.class );
assertThat( executableHelper.overrides( methodFromImpl, methodFromBase ) ).isFalse();
}
@Test
public void executableAsStringShouldReturnMethodNameWithBracesForParameterlessMethod() throws Exception {
assertEquals( ExecutableHelper.getExecutableAsString( "foo" ), "foo()" );
}
@Test
public void executableAsStringShouldReturnMethodNameWithSimpleParameterTypeNames() throws Exception {
assertEquals( ExecutableHelper.getExecutableAsString( "foo", int.class, Foo.class ), "foo(int, Foo)" );
}
@Test
@TestForIssue(jiraKey = "HV-861")
public void testBridgeMethodOverride() throws Exception {
Method setDataObjectBase = Node.class.getDeclaredMethod( "setData", Object.class );
Method setDataObject = MyNode.class.getDeclaredMethod( "setData", Object.class );
assertFalse(
executableHelper.overrides( setDataObject, setDataObjectBase ),
"MyNode#setData(Object) is the generated bridge method. It should be ignored."
);
Method setDataInteger = MyNode.class.getDeclaredMethod( "setData", Integer.class );
assertTrue(
executableHelper.overrides( setDataInteger, setDataObjectBase ),
"MyNode#setData(Integer) should override Node#setData(T)"
);
}
@Test
@TestForIssue(jiraKey = "HV-862")
public void shouldTakeVisibilityIntoAccountIfPrivate() throws Exception {
Method superType = Literature.class.getDeclaredMethod( "getAuthor" );
Method subType = GreekLiterature.class.getDeclaredMethod( "getAuthor" );
assertFalse(
executableHelper. overrides( subType, superType ),
"Literature#getAuthor() is private. It should not be possible to override it."
);
}
@Test
@TestForIssue(jiraKey = "HV-862")
public void shouldTakeVisibilityIntoAccountIfPackagePrivate() throws Exception {
Method superType = Literature.class.getDeclaredMethod( "getTitle" );
Method subType = Novella.class.getDeclaredMethod( "getTitle" );
assertFalse(
executableHelper.overrides( subType, superType ),
"Literature#getTitle() is package-private. It should not be possible to override it from a different package."
);
}
public abstract static class GenericServiceBase<T> {
public abstract void doSomething(T t);
}
public static class GenericServiceImpl1 extends GenericServiceBase<Number> {
@Override
public void doSomething(Number t) {
}
public void doSomething(Integer t) {
}
}
public abstract static class GenericServiceBaseExt extends GenericServiceBase<Number> {
}
public abstract static class GenericParameterizedServiceBaseExt<D> extends GenericServiceBase<D> {
}
public static class GenericServiceImpl2 extends GenericServiceBaseExt {
@Override
public void doSomething(Number t) {
}
public void doSomething(Integer t) {
}
}
public static class GenericServiceImpl3 extends GenericParameterizedServiceBaseExt<Number> {
@Override
public void doSomething(Number t) {
}
public void doSomething(Integer t) {
}
}
public abstract static class SimpleServiceBase {
public abstract void doSomething(Number t);
}
public abstract static class SimpleServiceBaseExt extends SimpleServiceBase {
}
public static class SimpleServiceImpl1 extends SimpleServiceBase {
@Override
public void doSomething(Number t) {
}
public void doSomething(Integer t) {
}
}
public static class SimpleServiceImpl2 extends SimpleServiceBaseExt {
@Override
public void doSomething(Number t) {
}
public void doSomething(Integer t) {
}
}
public static class ParameterizedSubType<U> extends GenericServiceBase<U> {
@Override
public void doSomething(U t) {
}
public void doSomething(Integer t) {
}
}
public interface GenericInterface<T> {
void doSomething(T t);
}
public static class GenericInterfaceImpl1 implements GenericInterface<Number> {
@Override
public void doSomething(Number t) {
}
public void doSomething(Integer t) {
}
}
public interface WildcardInterface<T extends Number> {
void doSomething(T t);
}
public static class WildcardInterfaceImpl implements WildcardInterface<Integer> {
@Override
public void doSomething(Integer t) {
}
public void doSomething(Long t) {
}
}
public static class Foo {
public Foo() {
}
public void zap() {
}
}
public static class Bar extends Foo {
public Bar() {
}
public Bar(int i, Date date) {
}
public void Foo() {
}
public void zip() {
}
public void zap(int i) {
}
@Override
public void zap() {
}
public void zap(int i, Date date) {
}
}
public interface IBaz {
void zap();
}
public static class Baz implements IBaz {
@Override
public void zap() {
}
}
@SuppressWarnings("unused")
private static class Qax {
public String getBar() {
return null;
}
public String getBar(String param) {
return null;
}
public static String getFoo() {
return null;
}
}
@SuppressWarnings("unused")
private static class SubQax extends Qax {
@Override
public String getBar() {
return null;
}
@Override
public String getBar(String param) {
return null;
}
public String getBar(Integer param) {
return null;
}
public String getFoo(Long param) {
return null;
}
public static String getFoo() {
return null;
}
public static String getFoo(Integer param) {
return null;
}
public static String getFoo(String param) {
return null;
}
}
@SuppressWarnings("unused")
public static class Literature {
private String getAuthor() {
return null;
}
String getTitle() {
return null;
}
}
@SuppressWarnings("unused")
private static class GreekLiterature extends Literature {
public String getAuthor() {
return null;
}
}
}