/** * EasyBeans * Copyright (C) 2006 Bull S.A.S. * Contact: easybeans@ow2.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * -------------------------------------------------------------------------- * $Id: InheritanceMethodResolver.java 5369 2010-02-24 14:58:19Z benoitf $ * -------------------------------------------------------------------------- */ package org.ow2.easybeans.deployment.annotations.helper.bean; import org.ow2.easybeans.asm.Opcodes; import org.ow2.easybeans.asm.Type; import org.ow2.easybeans.deployment.annotations.exceptions.ResolverException; import org.ow2.easybeans.deployment.metadata.ejbjar.EasyBeansEjbJarClassMetadata; import org.ow2.easybeans.deployment.metadata.ejbjar.EasyBeansEjbJarMethodMetadata; import org.ow2.util.log.Log; import org.ow2.util.log.LogFactory; import org.ow2.util.scan.api.metadata.IClassMetadata; import org.ow2.util.scan.api.metadata.structures.IMethod; import org.ow2.util.scan.impl.metadata.JMethod; /** * This class adds method meta data to bean class from the super class.<br> * * @author Florent Benoit * @see <a href="http://www.jcp.org/en/jsr/detail?id=220">EJB 3.0 Spec ?4.6.2</a><br><p> * A super class can't be a bean class (stateless, stateful, etc) so the * method metadata don't need to be cloned</p> */ public final class InheritanceMethodResolver { /** * java.lang.object internal name. */ private static final String JAVA_LANG_OBJECT = Type.getInternalName(Object.class); /** * Logger. */ private static Log logger = LogFactory.getLog(InheritanceMethodResolver.class); /** * Helper class, no public constructor. */ private InheritanceMethodResolver() { } /** * Found all method meta data of the super class and adds them to the class * being analyzed. * * @param classAnnotationMetadata class to analyze * * @throws ResolverException if the super class in not in the given ejb-jar */ public static void resolve(final EasyBeansEjbJarClassMetadata classAnnotationMetadata) throws ResolverException { addMethodMetadata(classAnnotationMetadata, classAnnotationMetadata, 1); } /** * Adds method meta data on the first class by iterating on the second given * class. * * @param beanclassAnnotationMetadata class where to add method metadata * @param visitingClassAnnotationMetadata * takes method metadata from super * class of the given class * * @throws ResolverException if a super class metadata is not found from * ejb-jar */ private static void addMethodMetadata(final EasyBeansEjbJarClassMetadata beanclassAnnotationMetadata, final EasyBeansEjbJarClassMetadata visitingClassAnnotationMetadata, int inheritanceLevel) throws ResolverException { // Analyze super classes of the given class String superClass = visitingClassAnnotationMetadata.getSuperName(); if (superClass != null) { // If super class is java.lang.Object, break the loop if (superClass.equals(JAVA_LANG_OBJECT)) { return; } // Get meta data of the super class EasyBeansEjbJarClassMetadata superClassMetadata = beanclassAnnotationMetadata.getEasyBeansLinkedClassMetadata(superClass); if (superClassMetadata == null) { // TODO : I18n throw new ResolverException("The class " + beanclassAnnotationMetadata + " extends the class " + superClass + "but this class seems to be outside of the ejb-jar"); } // Takes method metadata of the super class and adds them to the // bean class // Note : the flag inherited is set to true EasyBeansEjbJarMethodMetadata[] methodsToAnalyze = superClassMetadata.getMethodMetadataCollection() .toArray(new EasyBeansEjbJarMethodMetadata[superClassMetadata.getMethodMetadataCollection().size()]); for (EasyBeansEjbJarMethodMetadata methodAnnotationMetadata : methodsToAnalyze) { // skip inherited and private super call generated if (methodAnnotationMetadata.isInherited() || methodAnnotationMetadata.isPrivateSuperCallGenerated()) { continue; } // check that the method has not be redefined IMethod method = methodAnnotationMetadata.getJMethod(); EasyBeansEjbJarMethodMetadata beanMethod = beanclassAnnotationMetadata.getMethodMetadata(method); // overriding ? boolean superMethodIsPrivate = ((method.getAccess() & Opcodes.ACC_PRIVATE) == Opcodes.ACC_PRIVATE); // Handle case of super method which is private and we // already have the method, so we need to add a generated method on the super class if (beanMethod != null && superMethodIsPrivate && !visitingClassAnnotationMetadata.isBean()) { // Add a clone of the method to super class EasyBeansEjbJarMethodMetadata clonedMethodAnnotationMetadata = methodAnnotationMetadata.clone(methodAnnotationMetadata.getClassMetadata()); // Change metadata method name IMethod oldMethod = clonedMethodAnnotationMetadata.getJMethod(); IMethod newMethod = new JMethod(Opcodes.ACC_PUBLIC, oldMethod.getName() + superClassMetadata.getClassName().replace("/", ""), oldMethod.getDescriptor(), oldMethod .getSignature(), oldMethod.getExceptions()); // update metadata clonedMethodAnnotationMetadata.setJMethod(newMethod); clonedMethodAnnotationMetadata.setPrivateSuperCallGenerated(true, superClassMetadata, 0); clonedMethodAnnotationMetadata.setSuperPrivateMethodName(oldMethod.getName()); // Add the method superClassMetadata.addStandardMethodMetadata(clonedMethodAnnotationMetadata); // Update current parameters methodAnnotationMetadata = clonedMethodAnnotationMetadata; beanMethod = beanclassAnnotationMetadata.getMethodMetadata(newMethod); } // Add only if it is not present and super method is not private (else if super method is private, this is not an override) // Or if present and super method is private if (beanMethod == null || superMethodIsPrivate) { // Add a clone of the method to bean class EasyBeansEjbJarMethodMetadata clonedMethodAnnotationMetadata = methodAnnotationMetadata.clone(beanclassAnnotationMetadata); // method is inherited clonedMethodAnnotationMetadata.setPrivateSuperCallGenerated(false, (IClassMetadata) null, 0); clonedMethodAnnotationMetadata.setSuperPrivateMethodName(null); clonedMethodAnnotationMetadata.setInherited(true, superClassMetadata); // Final method ? ignore it /*if ((method.getAccess() & Opcodes.ACC_FINAL) == Opcodes.ACC_FINAL) { logger.warn("Ignoring final method ''{0}'' from the class ''{1}''", method.getName(), beanclassAnnotationMetadata.getClassName()); clonedMethodAnnotationMetadata.setIgnored(true); }*/ // add only if overrided if (beanMethod == null) { beanclassAnnotationMetadata.addStandardMethodMetadata(clonedMethodAnnotationMetadata); } // lifecycle / aroundInvoke if (clonedMethodAnnotationMetadata.isPostConstruct()) { beanclassAnnotationMetadata.addPostConstructMethodMetadata(clonedMethodAnnotationMetadata); } if (clonedMethodAnnotationMetadata.isPreDestroy()) { beanclassAnnotationMetadata.addPreDestroyMethodMetadata(clonedMethodAnnotationMetadata); } if (clonedMethodAnnotationMetadata.isPostActivate()) { beanclassAnnotationMetadata.addPostActivateMethodMetadata(clonedMethodAnnotationMetadata); } if (clonedMethodAnnotationMetadata.isPrePassivate()) { beanclassAnnotationMetadata.addPrePassivateMethodMetadata(clonedMethodAnnotationMetadata); } if (clonedMethodAnnotationMetadata.isAroundInvoke()) { beanclassAnnotationMetadata.addAroundInvokeMethodMetadata(clonedMethodAnnotationMetadata); } } } // Loop again addMethodMetadata(beanclassAnnotationMetadata, superClassMetadata, ++inheritanceLevel); } } }