001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.proxy2.stub; 019 020import java.lang.annotation.Annotation; 021 022import org.apache.commons.proxy2.interceptor.InterceptorUtils; 023 024public abstract class BaseAnnotationTrainer<S extends BaseAnnotationTrainer<S, A>, A extends Annotation> extends 025 BaseTrainer<S, A> 026{ 027 protected BaseAnnotationTrainer() 028 { 029 super(); 030 } 031 032 protected BaseAnnotationTrainer(Class<A> traineeType) 033 { 034 super(traineeType); 035 } 036 037 protected class WhenAnnotation<R> extends WhenObject<R> 038 { 039 public S thenStub(Class<R> type) 040 { 041 trainingContext().push(type); 042 trainingContext().then(InterceptorUtils.constant(trainingContext().pop(AnnotationInvoker.INSTANCE))); 043 return self(); 044 } 045 046 @Override 047 public S thenStub(BaseTrainer<?, R> trainer) 048 { 049 final R trainee = trainingContext().push(trainer.traineeType); 050 trainer.train(trainee); 051 trainingContext().then(InterceptorUtils.constant(trainingContext().pop(AnnotationInvoker.INSTANCE))); 052 return self(); 053 } 054 } 055 056 protected class WhenAnnotationArray<R> extends WhenObjectArray<R> 057 { 058 protected WhenAnnotationArray(Class<? extends R> componentType) 059 { 060 super(componentType); 061 } 062 063 @Override 064 public StubAnnotationArrayBuilder<R> thenBuildArray() 065 { 066 return new StubAnnotationArrayBuilder<R>(componentType); 067 } 068 } 069 070 protected class StubAnnotationArrayBuilder<R> extends StubArrayBuilder<R> 071 { 072 private final BaseTrainer<?, R> annotationTypeTrainer; 073 074 private <N extends Annotation> StubAnnotationArrayBuilder(final Class<? extends R> componentType) 075 { 076 super(componentType); 077 078 /* 079 * We know the only type of array method that can be hosted on an annotation is an annotation array. 080 * Therefore we declare a bogus annotation type parameter on this method which we use to create 081 * our AnnotationTypeTrainer, whose type parameter requires an annotation type. N == R 082 */ 083 @SuppressWarnings("unchecked") // we assume N == R 084 final Class<N> annotationType = (Class<N>) componentType; 085 @SuppressWarnings("unchecked") // and cast it back 086 final BaseTrainer<?, R> trainer = (BaseTrainer<?, R>) new AnnotationTypeTrainer<N>( 087 annotationType); 088 this.annotationTypeTrainer = trainer; 089 } 090 091 @Override 092 public StubAnnotationArrayBuilder<R> addElement(BaseTrainer<?, R> trainer) 093 { 094 final R trainee = trainingContext().push(trainer.traineeType); 095 096 annotationTypeTrainer.train(trainee); 097 trainer.train(trainee); 098 099 elements.add(trainingContext().<R> pop()); 100 return this; 101 } 102 } 103 104 @Override 105 public <R> WhenAnnotation<R> when(R expression) 106 { 107 return new WhenAnnotation<R>(); 108 } 109 110 @Override 111 public <R> WhenAnnotationArray<R> when(R[] expression) 112 { 113 @SuppressWarnings("unchecked") // we can reasonably say that the component type of an R[] is Class<? extends R>: 114 final Class<? extends R> componentType = (Class<? extends R>) expression.getClass().getComponentType(); 115 return new WhenAnnotationArray<R>(componentType); 116 } 117}