/*
 * Copyright 2002-2018 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.aop.support;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.IntroductionInfo;
import org.springframework.util.ClassUtils;

Support for implementations of IntroductionInfo.

Allows subclasses to conveniently add all interfaces from a given object, and to suppress interfaces that should not be added. Also allows for querying all introduced interfaces.

Author:Rod Johnson, Juergen Hoeller
/** * Support for implementations of {@link org.springframework.aop.IntroductionInfo}. * * <p>Allows subclasses to conveniently add all interfaces from a given object, * and to suppress interfaces that should not be added. Also allows for querying * all introduced interfaces. * * @author Rod Johnson * @author Juergen Hoeller */
@SuppressWarnings("serial") public class IntroductionInfoSupport implements IntroductionInfo, Serializable { protected final Set<Class<?>> publishedInterfaces = new LinkedHashSet<>(); private transient Map<Method, Boolean> rememberedMethods = new ConcurrentHashMap<>(32);
Suppress the specified interface, which may have been autodetected due to the delegate implementing it. Call this method to exclude internal interfaces from being visible at the proxy level.

Does nothing if the interface is not implemented by the delegate.

Params:
  • ifc – the interface to suppress
/** * Suppress the specified interface, which may have been autodetected * due to the delegate implementing it. Call this method to exclude * internal interfaces from being visible at the proxy level. * <p>Does nothing if the interface is not implemented by the delegate. * @param ifc the interface to suppress */
public void suppressInterface(Class<?> ifc) { this.publishedInterfaces.remove(ifc); } @Override public Class<?>[] getInterfaces() { return ClassUtils.toClassArray(this.publishedInterfaces); }
Check whether the specified interfaces is a published introduction interface.
Params:
  • ifc – the interface to check
Returns:whether the interface is part of this introduction
/** * Check whether the specified interfaces is a published introduction interface. * @param ifc the interface to check * @return whether the interface is part of this introduction */
public boolean implementsInterface(Class<?> ifc) { for (Class<?> pubIfc : this.publishedInterfaces) { if (ifc.isInterface() && ifc.isAssignableFrom(pubIfc)) { return true; } } return false; }
Publish all interfaces that the given delegate implements at the proxy level.
Params:
  • delegate – the delegate object
/** * Publish all interfaces that the given delegate implements at the proxy level. * @param delegate the delegate object */
protected void implementInterfacesOnObject(Object delegate) { this.publishedInterfaces.addAll(ClassUtils.getAllInterfacesAsSet(delegate)); }
Is this method on an introduced interface?
Params:
  • mi – the method invocation
Returns:whether the invoked method is on an introduced interface
/** * Is this method on an introduced interface? * @param mi the method invocation * @return whether the invoked method is on an introduced interface */
protected final boolean isMethodOnIntroducedInterface(MethodInvocation mi) { Boolean rememberedResult = this.rememberedMethods.get(mi.getMethod()); if (rememberedResult != null) { return rememberedResult; } else { // Work it out and cache it. boolean result = implementsInterface(mi.getMethod().getDeclaringClass()); this.rememberedMethods.put(mi.getMethod(), result); return result; } } //--------------------------------------------------------------------- // Serialization support //---------------------------------------------------------------------
This method is implemented only to restore the logger. We don't make the logger static as that would mean that subclasses would use this class's log category.
/** * This method is implemented only to restore the logger. * We don't make the logger static as that would mean that subclasses * would use this class's log category. */
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { // Rely on default serialization; just initialize state after deserialization. ois.defaultReadObject(); // Initialize transient fields. this.rememberedMethods = new ConcurrentHashMap<>(32); } }