/* * Copyright 2002-2017 the original author or authors. * * 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 org.springframework.core; import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.TypeVariable; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import org.junit.Test; import org.springframework.util.ReflectionUtils; import static org.junit.Assert.*; /** * @author Rob Harrop * @author Juergen Hoeller * @author Chris Beams */ @SuppressWarnings("rawtypes") public class BridgeMethodResolverTests { private static TypeVariable<?> findTypeVariable(Class<?> clazz, String name) { TypeVariable<?>[] variables = clazz.getTypeParameters(); for (TypeVariable<?> variable : variables) { if (variable.getName().equals(name)) { return variable; } } return null; } private static Method findMethodWithReturnType(String name, Class<?> returnType, Class<SettingsDaoImpl> targetType) { Method[] methods = targetType.getMethods(); for (Method m : methods) { if (m.getName().equals(name) && m.getReturnType().equals(returnType)) { return m; } } return null; } @Test public void testFindBridgedMethod() throws Exception { Method unbridged = MyFoo.class.getDeclaredMethod("someMethod", String.class, Object.class); Method bridged = MyFoo.class.getDeclaredMethod("someMethod", Serializable.class, Object.class); assertFalse(unbridged.isBridge()); assertTrue(bridged.isBridge()); assertEquals("Unbridged method not returned directly", unbridged, BridgeMethodResolver.findBridgedMethod(unbridged)); assertEquals("Incorrect bridged method returned", unbridged, BridgeMethodResolver.findBridgedMethod(bridged)); } @Test public void testFindBridgedVarargMethod() throws Exception { Method unbridged = MyFoo.class.getDeclaredMethod("someVarargMethod", String.class, Object[].class); Method bridged = MyFoo.class.getDeclaredMethod("someVarargMethod", Serializable.class, Object[].class); assertFalse(unbridged.isBridge()); assertTrue(bridged.isBridge()); assertEquals("Unbridged method not returned directly", unbridged, BridgeMethodResolver.findBridgedMethod(unbridged)); assertEquals("Incorrect bridged method returned", unbridged, BridgeMethodResolver.findBridgedMethod(bridged)); } @Test public void testFindBridgedMethodInHierarchy() throws Exception { Method bridgeMethod = DateAdder.class.getMethod("add", Object.class); assertTrue(bridgeMethod.isBridge()); Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod); assertFalse(bridgedMethod.isBridge()); assertEquals("add", bridgedMethod.getName()); assertEquals(1, bridgedMethod.getParameterCount()); assertEquals(Date.class, bridgedMethod.getParameterTypes()[0]); } @Test public void testIsBridgeMethodFor() throws Exception { Method bridged = MyBar.class.getDeclaredMethod("someMethod", String.class, Object.class); Method other = MyBar.class.getDeclaredMethod("someMethod", Integer.class, Object.class); Method bridge = MyBar.class.getDeclaredMethod("someMethod", Object.class, Object.class); assertTrue("Should be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, bridged, MyBar.class)); assertFalse("Should not be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, other, MyBar.class)); } @Test public void testDoubleParameterization() throws Exception { Method objectBridge = MyBoo.class.getDeclaredMethod("foo", Object.class); Method serializableBridge = MyBoo.class.getDeclaredMethod("foo", Serializable.class); Method stringFoo = MyBoo.class.getDeclaredMethod("foo", String.class); Method integerFoo = MyBoo.class.getDeclaredMethod("foo", Integer.class); assertEquals("foo(String) not resolved.", stringFoo, BridgeMethodResolver.findBridgedMethod(objectBridge)); assertEquals("foo(Integer) not resolved.", integerFoo, BridgeMethodResolver.findBridgedMethod(serializableBridge)); } @Test public void testFindBridgedMethodFromMultipleBridges() throws Exception { Method loadWithObjectReturn = findMethodWithReturnType("load", Object.class, SettingsDaoImpl.class); assertNotNull(loadWithObjectReturn); Method loadWithSettingsReturn = findMethodWithReturnType("load", Settings.class, SettingsDaoImpl.class); assertNotNull(loadWithSettingsReturn); assertNotSame(loadWithObjectReturn, loadWithSettingsReturn); Method method = SettingsDaoImpl.class.getMethod("load"); assertEquals(method, BridgeMethodResolver.findBridgedMethod(loadWithObjectReturn)); assertEquals(method, BridgeMethodResolver.findBridgedMethod(loadWithSettingsReturn)); } @Test public void testFindBridgedMethodFromParent() throws Exception { Method loadFromParentBridge = SettingsDaoImpl.class.getMethod("loadFromParent"); assertTrue(loadFromParentBridge.isBridge()); Method loadFromParent = AbstractDaoImpl.class.getMethod("loadFromParent"); assertFalse(loadFromParent.isBridge()); assertEquals(loadFromParent, BridgeMethodResolver.findBridgedMethod(loadFromParentBridge)); } @Test public void testWithSingleBoundParameterizedOnInstantiate() throws Exception { Method bridgeMethod = DelayQueue.class.getMethod("add", Object.class); assertTrue(bridgeMethod.isBridge()); Method actualMethod = DelayQueue.class.getMethod("add", Delayed.class); assertFalse(actualMethod.isBridge()); assertEquals(actualMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testWithDoubleBoundParameterizedOnInstantiate() throws Exception { Method bridgeMethod = SerializableBounded.class.getMethod("boundedOperation", Object.class); assertTrue(bridgeMethod.isBridge()); Method actualMethod = SerializableBounded.class.getMethod("boundedOperation", HashMap.class); assertFalse(actualMethod.isBridge()); assertEquals(actualMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testWithGenericParameter() throws Exception { Method[] methods = StringGenericParameter.class.getMethods(); Method bridgeMethod = null; Method bridgedMethod = null; for (Method method : methods) { if ("getFor".equals(method.getName()) && !method.getParameterTypes()[0].equals(Integer.class)) { if (method.getReturnType().equals(Object.class)) { bridgeMethod = method; } else { bridgedMethod = method; } } } assertTrue(bridgeMethod != null && bridgeMethod.isBridge()); assertTrue(bridgedMethod != null && !bridgedMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testOnAllMethods() throws Exception { Method[] methods = StringList.class.getMethods(); for (Method method : methods) { assertNotNull(BridgeMethodResolver.findBridgedMethod(method)); } } @Test public void testSPR2583() throws Exception { Method bridgedMethod = MessageBroadcasterImpl.class.getMethod("receive", MessageEvent.class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = MessageBroadcasterImpl.class.getMethod("receive", Event.class); assertTrue(bridgeMethod.isBridge()); Method otherMethod = MessageBroadcasterImpl.class.getMethod("receive", NewMessageEvent.class); assertFalse(otherMethod.isBridge()); assertFalse("Match identified incorrectly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, otherMethod, MessageBroadcasterImpl.class)); assertTrue("Match not found correctly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, bridgedMethod, MessageBroadcasterImpl.class)); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR2603() throws Exception { Method objectBridge = YourHomer.class.getDeclaredMethod("foo", Bounded.class); Method abstractBoundedFoo = YourHomer.class.getDeclaredMethod("foo", AbstractBounded.class); Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(objectBridge); assertEquals("foo(AbstractBounded) not resolved.", abstractBoundedFoo, bridgedMethod); } @Test public void testSPR2648() throws Exception { Method bridgeMethod = ReflectionUtils.findMethod(GenericSqlMapIntegerDao.class, "saveOrUpdate", Object.class); assertTrue(bridgeMethod != null && bridgeMethod.isBridge()); Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod); assertFalse(bridgedMethod.isBridge()); assertEquals("saveOrUpdate", bridgedMethod.getName()); } @Test public void testSPR2763() throws Exception { Method bridgedMethod = AbstractDao.class.getDeclaredMethod("save", Object.class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = UserDaoImpl.class.getDeclaredMethod("save", User.class); assertTrue(bridgeMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR3041() throws Exception { Method bridgedMethod = BusinessDao.class.getDeclaredMethod("save", Business.class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = BusinessDao.class.getDeclaredMethod("save", Object.class); assertTrue(bridgeMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR3173() throws Exception { Method bridgedMethod = UserDaoImpl.class.getDeclaredMethod("saveVararg", User.class, Object[].class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = UserDaoImpl.class.getDeclaredMethod("saveVararg", Object.class, Object[].class); assertTrue(bridgeMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR3304() throws Exception { Method bridgedMethod = MegaMessageProducerImpl.class.getDeclaredMethod("receive", MegaMessageEvent.class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = MegaMessageProducerImpl.class.getDeclaredMethod("receive", MegaEvent.class); assertTrue(bridgeMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR3324() throws Exception { Method bridgedMethod = BusinessDao.class.getDeclaredMethod("get", Long.class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = BusinessDao.class.getDeclaredMethod("get", Object.class); assertTrue(bridgeMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR3357() throws Exception { Method bridgedMethod = ExtendsAbstractImplementsInterface.class.getDeclaredMethod( "doSomething", DomainObjectExtendsSuper.class, Object.class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = ExtendsAbstractImplementsInterface.class.getDeclaredMethod( "doSomething", DomainObjectSuper.class, Object.class); assertTrue(bridgeMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR3485() throws Exception { Method bridgedMethod = DomainObject.class.getDeclaredMethod( "method2", ParameterType.class, byte[].class); assertFalse(bridgedMethod.isBridge()); Method bridgeMethod = DomainObject.class.getDeclaredMethod( "method2", Serializable.class, Object.class); assertTrue(bridgeMethod.isBridge()); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test public void testSPR3534() throws Exception { Method bridgeMethod = ReflectionUtils.findMethod(TestEmailProvider.class, "findBy", Object.class); assertTrue(bridgeMethod != null && bridgeMethod.isBridge()); Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod); assertFalse(bridgedMethod.isBridge()); assertEquals("findBy", bridgedMethod.getName()); } public static interface Foo<T extends Serializable> { void someMethod(T theArg, Object otherArg); void someVarargMethod(T theArg, Object... otherArg); } public static class MyFoo implements Foo<String> { public void someMethod(Integer theArg, Object otherArg) { } @Override public void someMethod(String theArg, Object otherArg) { } @Override public void someVarargMethod(String theArg, Object... otherArgs) { } } public static abstract class Bar<T> { void someMethod(Map<?, ?> m, Object otherArg) { } void someMethod(T theArg, Map<?, ?> m) { } abstract void someMethod(T theArg, Object otherArg); } public static abstract class InterBar<T> extends Bar<T> { } public static class MyBar extends InterBar<String> { @Override public void someMethod(String theArg, Object otherArg) { } public void someMethod(Integer theArg, Object otherArg) { } } public static interface Adder<T> { void add(T item); } public static abstract class AbstractDateAdder implements Adder<Date> { @Override public abstract void add(Date date); } public static class DateAdder extends AbstractDateAdder { @Override public void add(Date date) { } } public static class Enclosing<T> { public class Enclosed<S> { public class ReallyDeepNow<R> { void someMethod(S s, T t, R r) { } } } } public static class ExtendsEnclosing extends Enclosing<String> { public class ExtendsEnclosed extends Enclosed<Integer> { public class ExtendsReallyDeepNow extends ReallyDeepNow<Long> { @Override void someMethod(Integer s, String t, Long r) { throw new UnsupportedOperationException(); } } } } public static interface Boo<E, T extends Serializable> { void foo(E e); void foo(T t); } public static class MyBoo implements Boo<String, Integer> { @Override public void foo(String e) { throw new UnsupportedOperationException(); } @Override public void foo(Integer t) { throw new UnsupportedOperationException(); } } public static interface Settings { } public static interface ConcreteSettings extends Settings { } public static interface Dao<T, S> { T load(); S loadFromParent(); } public static interface SettingsDao<T extends Settings, S> extends Dao<T, S> { @Override T load(); } public static interface ConcreteSettingsDao extends SettingsDao<ConcreteSettings, String> { @Override String loadFromParent(); } static abstract class AbstractDaoImpl<T, S> implements Dao<T, S> { protected T object; protected S otherObject; protected AbstractDaoImpl(T object, S otherObject) { this.object = object; this.otherObject = otherObject; } //@Transactional(readOnly = true) @Override public S loadFromParent() { return otherObject; } } static class SettingsDaoImpl extends AbstractDaoImpl<ConcreteSettings, String> implements ConcreteSettingsDao { protected SettingsDaoImpl(ConcreteSettings object) { super(object, "From Parent"); } //@Transactional(readOnly = true) @Override public ConcreteSettings load() { return super.object; } } public static interface Bounded<E> { boolean boundedOperation(E e); } private static class AbstractBounded<E> implements Bounded<E> { @Override public boolean boundedOperation(E myE) { return true; } } private static class SerializableBounded<E extends HashMap & Delayed> extends AbstractBounded<E> { @Override public boolean boundedOperation(E myE) { return false; } } public static interface GenericParameter<T> { T getFor(Class<T> cls); } @SuppressWarnings("unused") private static class StringGenericParameter implements GenericParameter<String> { @Override public String getFor(Class<String> cls) { return "foo"; } public String getFor(Integer integer) { return "foo"; } } private static class StringList implements List<String> { @Override public int size() { throw new UnsupportedOperationException(); } @Override public boolean isEmpty() { throw new UnsupportedOperationException(); } @Override public boolean contains(Object o) { throw new UnsupportedOperationException(); } @Override public Iterator<String> iterator() { throw new UnsupportedOperationException(); } @Override public Object[] toArray() { throw new UnsupportedOperationException(); } @Override public <T> T[] toArray(T[] a) { throw new UnsupportedOperationException(); } @Override public boolean add(String o) { throw new UnsupportedOperationException(); } @Override public boolean remove(Object o) { throw new UnsupportedOperationException(); } @Override public boolean containsAll(Collection<?> c) { throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection<? extends String> c) { throw new UnsupportedOperationException(); } @Override public boolean addAll(int index, Collection<? extends String> c) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } @Override public String get(int index) { throw new UnsupportedOperationException(); } @Override public String set(int index, String element) { throw new UnsupportedOperationException(); } @Override public void add(int index, String element) { throw new UnsupportedOperationException(); } @Override public String remove(int index) { throw new UnsupportedOperationException(); } @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); } @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); } @Override public ListIterator<String> listIterator() { throw new UnsupportedOperationException(); } @Override public ListIterator<String> listIterator(int index) { throw new UnsupportedOperationException(); } @Override public List<String> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } } public static interface Event { int getPriority(); } public static class GenericEvent implements Event { private int priority; @Override public int getPriority() { return priority; } /** * Constructor that takes an event priority */ public GenericEvent(int priority) { this.priority = priority; } /** * Default Constructor */ public GenericEvent() { } } public static interface UserInitiatedEvent { //public Session getInitiatorSession(); } public static abstract class BaseUserInitiatedEvent extends GenericEvent implements UserInitiatedEvent { } public static class MessageEvent extends BaseUserInitiatedEvent { } public static interface Channel<E extends Event> { void send(E event); void subscribe(final Receiver<E> receiver, Class<E> event); void unsubscribe(final Receiver<E> receiver, Class<E> event); } public static interface Broadcaster { } public static interface EventBroadcaster extends Broadcaster { public void subscribe(); public void unsubscribe(); public void setChannel(Channel<?> channel); } public static class GenericBroadcasterImpl implements Broadcaster { } @SuppressWarnings({ "unused", "unchecked" }) public static abstract class GenericEventBroadcasterImpl<T extends Event> extends GenericBroadcasterImpl implements EventBroadcaster { private Class<T>[] subscribingEvents; private Channel<T> channel; /** * Abstract method to retrieve instance of subclass * * @return receiver instance */ public abstract Receiver<T> getInstance(); @Override public void setChannel(Channel channel) { this.channel = channel; } private String beanName; public void setBeanName(String name) { this.beanName = name; } @Override public void subscribe() { } @Override public void unsubscribe() { } public GenericEventBroadcasterImpl(Class<? extends T>... events) { } } public static interface Receiver<E extends Event> { void receive(E event); } public static interface MessageBroadcaster extends Receiver<MessageEvent> { } public static class RemovedMessageEvent extends MessageEvent { } public static class NewMessageEvent extends MessageEvent { } public static class ModifiedMessageEvent extends MessageEvent { } @SuppressWarnings("unchecked") public static class MessageBroadcasterImpl extends GenericEventBroadcasterImpl<MessageEvent> implements MessageBroadcaster { public MessageBroadcasterImpl() { super(NewMessageEvent.class); } @Override public void receive(MessageEvent event) { throw new UnsupportedOperationException("should not be called, use subclassed events"); } public void receive(NewMessageEvent event) { } @Override public Receiver<MessageEvent> getInstance() { return null; } public void receive(RemovedMessageEvent event) { } public void receive(ModifiedMessageEvent event) { } } //----------------------------- // SPR-2454 Test Classes //----------------------------- public static interface SimpleGenericRepository<T> { public Class<T> getPersistentClass(); List<T> findByQuery(); List<T> findAll(); T refresh(T entity); T saveOrUpdate(T entity); void delete(Collection<T> entities); } public static interface RepositoryRegistry { <T> SimpleGenericRepository<T> getFor(Class<T> entityType); } @SuppressWarnings("unchecked") public static class SettableRepositoryRegistry<R extends SimpleGenericRepository<?>> implements RepositoryRegistry { protected void injectInto(R rep) { } public void register(R rep) { } public void register(R... reps) { } public void setRepos(R... reps) { } @Override public <T> SimpleGenericRepository<T> getFor(Class<T> entityType) { return null; } public void afterPropertiesSet() throws Exception { } } public static interface ConvenientGenericRepository<T, ID extends Serializable> extends SimpleGenericRepository<T> { T findById(ID id, boolean lock); List<T> findByExample(T exampleInstance); void delete(ID id); void delete(T entity); } public static class GenericHibernateRepository<T, ID extends Serializable> implements ConvenientGenericRepository<T, ID> { /** * @param c Mandatory. The domain class this repository is responsible for. */ // Since it is impossible to determine the actual type of a type // parameter (!), we resort to requiring the caller to provide the // actual type as parameter, too. // Not set in a constructor to enable easy CGLIB-proxying (passing // constructor arguments to Spring AOP proxies is quite cumbersome). public void setPersistentClass(Class<T> c) { } @Override public Class<T> getPersistentClass() { return null; } @Override public T findById(ID id, boolean lock) { return null; } @Override public List<T> findAll() { return null; } @Override public List<T> findByExample(T exampleInstance) { return null; } @Override public List<T> findByQuery() { return null; } @Override public T saveOrUpdate(T entity) { return null; } @Override public void delete(T entity) { } @Override public T refresh(T entity) { return null; } @Override public void delete(ID id) { } @Override public void delete(Collection<T> entities) { } } public static class HibernateRepositoryRegistry extends SettableRepositoryRegistry<GenericHibernateRepository<?, ?>> { @Override public void injectInto(GenericHibernateRepository<?, ?> rep) { } @Override public <T> GenericHibernateRepository<T, ?> getFor(Class<T> entityType) { return null; } } //------------------- // SPR-2603 classes //------------------- public static interface Homer<E> { void foo(E e); } public static class MyHomer<T extends Bounded<T>, L extends T> implements Homer<L> { @Override public void foo(L t) { throw new UnsupportedOperationException(); } } public static class YourHomer<T extends AbstractBounded<T>, L extends T> extends MyHomer<T, L> { @Override public void foo(L t) { throw new UnsupportedOperationException(); } } public static interface GenericDao<T> { public void saveOrUpdate(T t); } public static interface ConvenienceGenericDao<T> extends GenericDao<T> { } public static class GenericSqlMapDao<T extends Serializable> implements ConvenienceGenericDao<T> { @Override public void saveOrUpdate(T t) { throw new UnsupportedOperationException(); } } public static class GenericSqlMapIntegerDao<T extends Number> extends GenericSqlMapDao<T> { @Override public void saveOrUpdate(T t) { } } public static class Permission { } public static class User { } public static interface UserDao { //@Transactional void save(User user); //@Transactional void save(Permission perm); } public static abstract class AbstractDao<T> { public void save(T t) { } public void saveVararg(T t, Object... args) { } } public static class UserDaoImpl extends AbstractDao<User> implements UserDao { @Override public void save(Permission perm) { } @Override public void saveVararg(User user, Object... args) { } } public static interface DaoInterface<T, P> { T get(P id); } public static abstract class BusinessGenericDao<T, PK extends Serializable> implements DaoInterface<T, PK> { public void save(T object) { } } public static class Business<T> { } public static class BusinessDao extends BusinessGenericDao<Business<?>, Long> { @Override public void save(Business<?> business) { } @Override public Business<?> get(Long id) { return null; } public Business<?> get(String code) { return null; } } //------------------- // SPR-3304 classes //------------------- private static class MegaEvent { } private static class MegaMessageEvent extends MegaEvent { } private static class NewMegaMessageEvent extends MegaEvent { } private static class ModifiedMegaMessageEvent extends MegaEvent { } public static interface MegaReceiver<E extends MegaEvent> { void receive(E event); } public static interface MegaMessageProducer extends MegaReceiver<MegaMessageEvent> { } private static class Other<S,E> { } @SuppressWarnings("unused") private static class MegaMessageProducerImpl extends Other<Long, String> implements MegaMessageProducer { public void receive(NewMegaMessageEvent event) { throw new UnsupportedOperationException(); } public void receive(ModifiedMegaMessageEvent event) { throw new UnsupportedOperationException(); } @Override public void receive(MegaMessageEvent event) { throw new UnsupportedOperationException(); } } //------------------- // SPR-3357 classes //------------------- private static class DomainObjectSuper { } private static class DomainObjectExtendsSuper extends DomainObjectSuper { } public static interface IGenericInterface<D extends DomainObjectSuper> { <T> void doSomething(final D domainObject, final T value); } @SuppressWarnings("unused") private static abstract class AbstractImplementsInterface<D extends DomainObjectSuper> implements IGenericInterface<D> { @Override public <T> void doSomething(D domainObject, T value) { } public void anotherBaseMethod() { } } private static class ExtendsAbstractImplementsInterface extends AbstractImplementsInterface<DomainObjectExtendsSuper> { @Override public <T> void doSomething(DomainObjectExtendsSuper domainObject, T value) { super.doSomething(domainObject, value); } } //------------------- // SPR-3485 classes //------------------- @SuppressWarnings("serial") private static class ParameterType implements Serializable { } private static class AbstractDomainObject<P extends Serializable, R> { public R method1(P p) { return null; } public void method2(P p, R r) { } } private static class DomainObject extends AbstractDomainObject<ParameterType, byte[]> { @Override public byte[] method1(ParameterType p) { return super.method1(p); } @Override public void method2(ParameterType p, byte[] r) { super.method2(p, r); } } //------------------- // SPR-3534 classes //------------------- public static interface SearchProvider<RETURN_TYPE, CONDITIONS_TYPE> { Collection<RETURN_TYPE> findBy(CONDITIONS_TYPE conditions); } public static class SearchConditions { } public static interface IExternalMessageProvider<S extends ExternalMessage, T extends ExternalMessageSearchConditions<?>> extends SearchProvider<S, T> { } public static class ExternalMessage { } public static class ExternalMessageSearchConditions<T extends ExternalMessage> extends SearchConditions { } public static class ExternalMessageProvider<S extends ExternalMessage, T extends ExternalMessageSearchConditions<S>> implements IExternalMessageProvider<S, T> { @Override public Collection<S> findBy(T conditions) { return null; } } public static class EmailMessage extends ExternalMessage { } public static class EmailSearchConditions extends ExternalMessageSearchConditions<EmailMessage> { } public static class EmailMessageProvider extends ExternalMessageProvider<EmailMessage, EmailSearchConditions> { } public static class TestEmailProvider extends EmailMessageProvider { @Override public Collection<EmailMessage> findBy(EmailSearchConditions conditions) { return null; } } }