001 /* 002 * Copyright 2013 Google Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package com.google.gwtmockito.fakes; 017 018 import com.google.gwt.core.client.GWT; 019 import com.google.gwt.uibinder.client.UiBinder; 020 import com.google.gwt.uibinder.client.UiField; 021 022 import java.lang.reflect.Field; 023 import java.lang.reflect.InvocationHandler; 024 import java.lang.reflect.Method; 025 import java.lang.reflect.ParameterizedType; 026 import java.lang.reflect.Proxy; 027 import java.util.Arrays; 028 import java.util.LinkedList; 029 import java.util.List; 030 031 /** 032 * Provides fake implementations of {@link UiBinder}. The fake implementation 033 * populates all (non-provided) {@link UiField} in the target type with objects 034 * obtained from GWT.create. {@link com.google.gwtmockito.GwtMockito} can be 035 * used to control values returned from GWT.create and hence affect how fields 036 * are populated. 037 * 038 * @author ekuefler@google.com (Erik Kuefler) 039 */ 040 public class FakeUiBinderProvider implements FakeProvider<UiBinder<?, ?>>{ 041 042 /** 043 * Returns a new instance of FakeUiBinder that implements the given interface. 044 * This is accomplished by returning a dynamic proxy object that delegates 045 * calls to a backing FakeUiBinder. 046 * 047 * @param type interface to be implemented by the returned type. This must 048 * represent an interface that directly extends {@link UiBinder}. 049 */ 050 @Override 051 public UiBinder<?, ?> getFake(final Class<?> type) { 052 return (UiBinder<?, ?>) Proxy.newProxyInstance( 053 FakeUiBinderProvider.class.getClassLoader(), 054 new Class<?>[] {type}, 055 new InvocationHandler() { 056 @Override 057 public Object invoke(Object proxy, Method method, Object[] args) throws Exception { 058 // createAndBindUi is the only method defined by UiBinder 059 for (Field field : getAllFields(args[0].getClass())) { 060 if (field.isAnnotationPresent(UiField.class) 061 && !field.getAnnotation(UiField.class).provided()) { 062 field.setAccessible(true); 063 field.set(args[0], GWT.create(field.getType())); 064 } 065 } 066 return GWT.create(getUiRootType(type)); 067 } 068 }); 069 } 070 071 private <T> Class<?> getUiRootType(Class<T> type) { 072 // The UI root type is the first generic type parameter of the UiBinder 073 ParameterizedType parameterizedType = (ParameterizedType) type.getGenericInterfaces()[0]; 074 Class<?> uiRootType = (Class<?>) parameterizedType.getActualTypeArguments()[0]; 075 return uiRootType; 076 } 077 078 private List<Field> getAllFields(Class<?> type) { 079 List<Field> fields = new LinkedList<Field>(); 080 fields.addAll(Arrays.asList(type.getDeclaredFields())); 081 if (type.getSuperclass() != null) { 082 fields.addAll(getAllFields(type.getSuperclass())); 083 } 084 return fields; 085 } 086 }