/*
* Copyright 2015 ArcBees Inc.
*
* 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 com.gwtplatform.dispatch.rest.processors;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import org.mockito.MockingDetails;
import com.google.gwt.dev.util.collect.Maps;
import static java.util.Arrays.asList;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockingDetails;
/**
* Improvements to be done in order to be moved to tools:
* - Support no, one or many annotations
* - Support setting no, one or many annotation values.
*/
public class AnnotatedElementBuilder {
private final Element element;
private final Class<? extends Annotation> annotationClass;
private final AnnotationMirror annotationMirror;
public AnnotatedElementBuilder(Annotation annotation) {
this(mock(Element.class), annotation);
}
public AnnotatedElementBuilder(
Element element,
Annotation annotation) {
this(element, findAnnotationClass(annotation));
// TODO : Not sure why Intellij fails without this cast..
// noinspection RedundantCast
given(element.getAnnotation((Class<Annotation>) annotationClass)).willReturn(annotation);
}
public AnnotatedElementBuilder(
Element element,
Class<? extends Annotation> annotationClass) {
this.element = element;
this.annotationClass = annotationClass;
this.annotationMirror = mock(AnnotationMirror.class);
initialize();
}
@SuppressWarnings("unchecked")
private static Class<? extends Annotation> findAnnotationClass(Annotation annotation) {
Class<? extends Annotation> clazz;
MockingDetails mockingDetails = mockingDetails(annotation);
if (mockingDetails.isMock() || mockingDetails.isSpy()) {
clazz = (Class<? extends Annotation>) annotation.getClass().getInterfaces()[0];
} else {
clazz = annotation.getClass();
}
return clazz;
}
public static Element stubElementWithoutAnnotations() {
Element element = mock(Element.class);
given(element.getAnnotationMirrors()).willReturn((List) new ArrayList<>());
return element;
}
private void initialize() {
DeclaredType annotationType = mock(DeclaredType.class);
TypeElement annotationElement = mock(TypeElement.class);
Name annotationName = mock(Name.class);
setAnnotationMirrors();
given(annotationMirror.getAnnotationType()).willReturn(annotationType);
given(annotationType.asElement()).willReturn(annotationElement);
given(annotationElement.accept(any(ElementVisitor.class), any())).willReturn(annotationElement);
given(annotationElement.getQualifiedName()).willReturn(annotationName);
given(annotationName.contentEquals(annotationClass.getCanonicalName())).willReturn(true);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void setAnnotationMirrors() {
given(element.getAnnotationMirrors()).willReturn((List) asList(annotationMirror));
}
public void setAnnotationValue(String name, Object value) {
ExecutableElement annotationValueMethod = mock(ExecutableElement.class);
Name annotationValueMethodName = mock(Name.class);
AnnotationValue annotationValue = mock(AnnotationValue.class);
given(annotationValueMethod.getSimpleName()).willReturn(annotationValueMethodName);
given(annotationValueMethodName.contentEquals(name)).willReturn(true);
given(annotationValue.getValue()).willReturn(value);
setAnnotationValues(annotationValueMethod, annotationValue);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void setAnnotationValues(ExecutableElement annotationValueMethod, AnnotationValue annotationValue) {
given(annotationMirror.getElementValues())
.willReturn((Map) Maps.create(annotationValueMethod, annotationValue));
}
public Element getElement() {
return element;
}
}