/* * Copyright 2013 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.data.hadoop.config.common.annotation; import java.util.ArrayList; import java.util.List; import org.springframework.core.GenericTypeResolver; /** * A base class for {@link AnnotationConfigurer} that allows subclasses to only * implement the methods they are interested in. It also provides a mechanism * for using the {@link AnnotationConfigurer} and when done gaining access to the * {@link AnnotationBuilder} that is being configured. * * @author Rob Winch * @author Janne Valkealahti * * @param <O> The Object being built by B * @param <I> The type of the builder * @param <B> The Builder that is building O and is configured by {@link AnnotationConfigurerAdapter} */ public abstract class AnnotationConfigurerAdapter<O,I,B extends AnnotationBuilder<O>> implements AnnotationConfigurer<O,B> { private B builder; private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor(); @Override public void init(B builder) throws Exception {} @Override public void configure(B builder) throws Exception {} /** * Return the {@link AnnotationBuilder} when done using the * {@link AnnotationConfigurer}. This is useful for method chaining. * * @return the {@link AnnotationBuilder} */ @SuppressWarnings("unchecked") public I and() { // we're either casting to itself or its interface return (I) getBuilder(); } /** * Gets the {@link AnnotationBuilder}. Cannot be null. This method * throws {@link IllegalStateException} if {@link AnnotationBuilder} is null. * * @return the {@link AnnotationBuilder} */ protected final B getBuilder() { if(builder == null) { throw new IllegalStateException("annotationBuilder cannot be null"); } return builder; } /** * Adds an {@link ObjectPostProcessor} to be used for this * {@link AnnotationConfigurerAdapter}. The default implementation does * nothing to the object. * * @param objectPostProcessor the {@link ObjectPostProcessor} to use */ public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) { this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor); } /** * Sets the {@link AnnotationBuilder} to be used. This is automatically set * when using * {@link AbstractConfiguredAnnotationBuilder#apply(AnnotationConfigurerAdapter)} * * @param builder the {@link AnnotationBuilder} to set */ public void setBuilder(B builder) { this.builder = builder; } /** * An {@link ObjectPostProcessor} that delegates work to numerous * {@link ObjectPostProcessor} implementations. */ private static final class CompositeObjectPostProcessor implements ObjectPostProcessor<Object> { private List<ObjectPostProcessor<? extends Object>> postProcessors = new ArrayList<ObjectPostProcessor<?>>(); @Override @SuppressWarnings({ "rawtypes", "unchecked" }) public Object postProcess(Object object) { for(ObjectPostProcessor opp : postProcessors) { Class<?> oppClass = opp.getClass(); Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,ObjectPostProcessor.class); if(oppType == null || oppType.isAssignableFrom(object.getClass())) { object = opp.postProcess(object); } } return object; } /** * Adds an {@link ObjectPostProcessor} to use * * @param objectPostProcessor the {@link ObjectPostProcessor} to add * @return true if the {@link ObjectPostProcessor} was added, else false */ private boolean addObjectPostProcessor(ObjectPostProcessor<? extends Object> objectPostProcessor) { return this.postProcessors.add(objectPostProcessor); } } @Override public boolean isAssignable(AnnotationBuilder<O> builder) { return true; } }