/******************************************************************************* * Copyright (c) 2007, 2014 Spring IDE Developers * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Spring IDE Developers - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.beans.core.internal.model.validation.rules; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.ide.eclipse.beans.core.internal.model.BeanReplaceMethodOverride; import org.springframework.ide.eclipse.beans.core.internal.model.BeansModelUtils; import org.springframework.ide.eclipse.beans.core.model.IBean; import org.springframework.ide.eclipse.beans.core.model.IBeanMethodOverride; import org.springframework.ide.eclipse.beans.core.model.validation.AbstractNonInfrastructureBeanValidationRule; import org.springframework.ide.eclipse.beans.core.model.validation.IBeansValidationContext; import org.springframework.ide.eclipse.core.java.Introspector; import org.springframework.ide.eclipse.core.model.IModelElement; import org.springframework.ide.eclipse.core.model.validation.IValidationRule; import org.springsource.ide.eclipse.commons.core.SpringCoreUtils; /** * Validates a given {@link IBeanMethodOverride#getBeanName()} in bean class. * @author Christian Dupuis * @since 2.0.2 */ public class BeanMethodOverrideRule extends AbstractNonInfrastructureBeanValidationRule implements IValidationRule<IBeanMethodOverride, IBeansValidationContext> { /** * Checks if this validation rule supports given <code>element</code> and <code>context</code>. * @return true if and only element is a {@link IBeanMethodOverride} and the parent element a * {@link IBean} */ @Override protected boolean supportsModelElementForNonInfrastructureBean(IModelElement element, IBeansValidationContext context) { return element instanceof IBeanMethodOverride && element.getElementParent() instanceof IBean; } /** * Validates the given {@link IBeanMethodOverride} for matching methods to override. */ public void validate(IBeanMethodOverride override, IBeansValidationContext context, IProgressMonitor monitor) { IBean bean = (IBean) override.getElementParent(); AbstractBeanDefinition mergedBd = (AbstractBeanDefinition) BeansModelUtils .getMergedBeanDefinition(bean, context.getContextElement()); String mergedClassName = mergedBd.getBeanClassName(); if (mergedClassName != null && !SpringCoreUtils.hasPlaceHolder(mergedClassName)) { IType type = ValidationRuleUtils.extractBeanClass(mergedBd, bean, mergedClassName, context); if (type != null) { if (override.getType() == IBeanMethodOverride.TYPE.LOOKUP) { validateLookupOverride(override, type, context); } else if (override.getType() == IBeanMethodOverride.TYPE.REPLACE) { validateReplaceOverride(override, type, context); } } } } /** * Validates if the given bean type has a method that matches the following signature: * <p> * * <pre> * <public|protected> [abstract] <return-type> theMethodName(..); * </pre> * * @param override the MethodOverride to check * @param type the bean type * @param context the validation context */ private void validateReplaceOverride(IBeanMethodOverride override, IType type, IBeansValidationContext context) { if (override instanceof BeanReplaceMethodOverride) { String methodName = override.getMethodName(); try { // TODO CD once typeIdentifier get exposed in Spring core add // parameter check to following method check // ((ReplaceOverride)((BeanReplaceMethodOverride) // override).getMethodOverride()).getTypeIdentifier(); Set<IMethod> methods = Introspector.getAllMethods(type); for (IMethod method : methods) { if (method.getElementName().equals(methodName) && (Flags.isProtected(method.getFlags()) || Flags.isPublic(method .getFlags()))) { return; } } // if we reach here, no matching method could be found! context.error(override, "UNDEFINED_REPLACE_METHOD", "Replace-method '" + methodName + "' not found in bean class '" + type.getFullyQualifiedName() + "'"); } catch (JavaModelException e) { } } } /** * Validates if the given bean type has a method that matches the following signature: * <p> * * <pre> * <public|protected> [abstract] <return-type> theMethodName(no-arguments); * </pre> * * @param override the MethodOverride to check * @param type the bean type * @param context the validation context */ private void validateLookupOverride(IBeanMethodOverride override, IType type, IBeansValidationContext context) { String methodName = override.getMethodName(); try { Set<IMethod> methods = Introspector.findAllNoParameterMethods(type, methodName); for (IMethod method : methods) { if (type.isInterface() || Flags.isProtected(method.getFlags()) || Flags.isPublic(method.getFlags())) { return; } } // if we reach here, no matching method could be found! context.error(override, "UNDEFINED_LOOKUP_METHOD", "Lookup-method '" + methodName + "' not found in bean class '" + type.getFullyQualifiedName() + "'"); } catch (JavaModelException e) { } } }