blob: 8a070859a14c49c70157e6debd7c908906e1f7d4 [file] [log] [blame]
/*
* Copyright 2011 Google 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.google.web.bindery.requestfactory.apt;
import com.google.gwt.dev.util.Name.BinaryName;
import com.google.web.bindery.requestfactory.shared.JsonRpcService;
import com.google.web.bindery.requestfactory.shared.Service;
import com.google.web.bindery.requestfactory.shared.ServiceName;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeMirror;
/**
* Scans a RequestContext declaration. This visitor will call out to the State
* object to validate the types that it encounters.
*/
class RequestContextScanner extends ScannerBase<Void> {
@Override
public Void visitExecutable(ExecutableElement x, State state) {
if (shouldIgnore(x, state)) {
return null;
}
TypeMirror returnType = x.getReturnType();
if (state.types.isAssignable(returnType, state.requestType)) {
// Extract Request<Foo> type
DeclaredType asRequest = (DeclaredType) State.viewAs(state.requestType, returnType, state);
if (asRequest.getTypeArguments().isEmpty()) {
state.poison(x, Messages.rawType());
} else {
TypeMirror requestReturn = asRequest.getTypeArguments().get(0);
if (!state.isTransportableType(requestReturn)) {
state.poison(x, Messages.untransportableType(requestReturn));
}
}
} else if (state.types.isAssignable(returnType, state.instanceRequestType)) {
// Extract InstanceRequest<FooProxy, String>
DeclaredType asInstanceRequest =
(DeclaredType) State.viewAs(state.instanceRequestType, returnType, state);
if (asInstanceRequest.getTypeArguments().isEmpty()) {
state.poison(x, Messages.rawType());
} else {
TypeMirror instanceType = asInstanceRequest.getTypeArguments().get(0);
state.maybeScanProxy((TypeElement) state.types.asElement(instanceType));
TypeMirror requestReturn = asInstanceRequest.getTypeArguments().get(1);
if (!state.isTransportableType(requestReturn)) {
state.poison(x, Messages.untransportableType(requestReturn));
}
}
} else if (isSetter(x, state)) {
// Parameter checked in visitVariable
} else {
state.poison(x, Messages.contextRequiredReturnTypes(state.requestType.asElement()
.getSimpleName(), state.instanceRequestType.asElement().getSimpleName()));
}
return super.visitExecutable(x, state);
}
@Override
public Void visitType(TypeElement x, State state) {
Service service = x.getAnnotation(Service.class);
ServiceName serviceName = x.getAnnotation(ServiceName.class);
JsonRpcService jsonRpcService = x.getAnnotation(JsonRpcService.class);
if (service != null) {
poisonIfAnnotationPresent(state, x, serviceName, jsonRpcService);
// See javadoc on Element.getAnnotation() for why it works this way
try {
service.value();
throw new RuntimeException("Should not reach here");
} catch (MirroredTypeException expected) {
TypeMirror type = expected.getTypeMirror();
state.addMapping(x, (TypeElement) state.types.asElement(type));
}
}
if (serviceName != null) {
poisonIfAnnotationPresent(state, x, jsonRpcService);
TypeElement domain =
state.elements.getTypeElement(BinaryName.toSourceName(serviceName.value()));
if (domain == null) {
state.warn(x, Messages.contextMissingDomainType(serviceName.value()));
}
state.addMapping(x, domain);
}
scanAllInheritedMethods(x, state);
state.checkExtraTypes(x);
return null;
}
@Override
public Void visitTypeParameter(TypeParameterElement x, State state) {
for (TypeMirror bound : x.getBounds()) {
if (!state.isTransportableType(bound)) {
state.poison(x, Messages.untransportableType(bound));
}
}
return super.visitTypeParameter(x, state);
}
@Override
public Void visitVariable(VariableElement x, State state) {
if (!state.isTransportableType(x.asType())) {
state.poison(x, Messages.untransportableType(x.asType()));
}
return super.visitVariable(x, state);
}
}