PageRenderTime 23ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/gwt-test-utils/src/main/java/com/octo/gwt/test/uibinder/UiBinderInstanciator.java

http://gwt-test-utils.googlecode.com/
Java | 196 lines | 149 code | 38 blank | 9 comment | 37 complexity | 2e64e7e9b6904ef7cd90f401ae20fa36 MD5 | raw file
  1. package com.octo.gwt.test.uibinder;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import java.util.Map;
  8. import com.google.gwt.core.client.GWT;
  9. import com.google.gwt.uibinder.client.UiConstructor;
  10. import com.google.gwt.uibinder.client.UiFactory;
  11. import com.google.gwt.uibinder.client.UiField;
  12. import com.google.gwt.user.client.ui.IsWidget;
  13. import com.google.gwt.user.client.ui.UIObject;
  14. import com.octo.gwt.test.exceptions.GwtTestUiBinderException;
  15. import com.octo.gwt.test.internal.GwtConfig;
  16. import com.octo.gwt.test.utils.GwtReflectionUtils;
  17. /**
  18. * Class responsible for Object instantiations. It handles provided
  19. * {@link UiField}, {@link UiFactory} fields and {@link UiConstructor} fields.
  20. *
  21. * @author Gael Lazzari
  22. *
  23. */
  24. @SuppressWarnings("unchecked")
  25. class UiBinderInstanciator {
  26. static <U> U getInstance(Class<U> clazz, Map<String, Object> attributes,
  27. Object owner) {
  28. U instance = getProvidedUiField(clazz, owner);
  29. if (instance == null) {
  30. instance = getObjectFromUiFactory(clazz, owner);
  31. }
  32. if (instance == null) {
  33. instance = getObjectFromUiConstructor(clazz, attributes);
  34. }
  35. if (instance == null && !UIObject.class.isAssignableFrom(clazz)
  36. && !IsWidget.class.isAssignableFrom(clazz)) {
  37. instance = GWT.create(clazz);
  38. }
  39. return instance;
  40. }
  41. private static List<Object> extractArgs(String[] argNames,
  42. Map<String, Object> attributes) {
  43. List<Object> args = new ArrayList<Object>();
  44. for (String argName : argNames) {
  45. Object arg = attributes.get(argName);
  46. if (arg == null) {
  47. // the widget .ui.xml declaration does not match with this
  48. // @UiConstructor
  49. return null;
  50. }
  51. args.add(arg);
  52. }
  53. return args;
  54. }
  55. private static <U> U getObjectFromUiConstructor(Class<U> clazz,
  56. Map<String, Object> attributes) {
  57. List<String[]> registeredUiConstructors = GwtConfig.get().getUiConstructors(
  58. clazz);
  59. boolean hasUiConstructor = false;
  60. for (Constructor<?> cons : clazz.getDeclaredConstructors()) {
  61. if (cons.getAnnotation(UiConstructor.class) != null) {
  62. hasUiConstructor = true;
  63. if (registeredUiConstructors == null) {
  64. throw new GwtTestUiBinderException(
  65. "gwt-test-utils has found a @UiConstructor in '"
  66. + clazz.getName()
  67. + "' which isn't registered. You should register it by calling the 'registerUiConstructor' with the approriate parameters in your test class");
  68. }
  69. Constructor<U> uiConstructor = (Constructor<U>) cons;
  70. for (String[] argNames : registeredUiConstructors) {
  71. List<Object> potentialArgs = extractArgs(argNames, attributes);
  72. if (potentialArgs != null && matchs(uiConstructor, potentialArgs)) {
  73. return instanciate(uiConstructor, potentialArgs);
  74. }
  75. }
  76. }
  77. }
  78. if (!hasUiConstructor) {
  79. return null;
  80. } else {
  81. throw new GwtTestUiBinderException(
  82. "gwt-test-utils has found at least one @UiConstructor in '"
  83. + clazz.getName()
  84. + "' which isn't registered well. You should register it by calling the 'registerUiConstructor' with the approriate parameters in your test class");
  85. }
  86. }
  87. private static <U> U getObjectFromUiFactory(Class<U> clazz, Object owner) {
  88. Map<Method, UiFactory> map = GwtReflectionUtils.getAnnotatedMethod(
  89. owner.getClass(), UiFactory.class);
  90. List<Method> compatibleFactories = new ArrayList<Method>();
  91. for (Method factoryMethod : map.keySet()) {
  92. if (clazz.isAssignableFrom(factoryMethod.getReturnType())) {
  93. compatibleFactories.add(factoryMethod);
  94. }
  95. }
  96. switch (compatibleFactories.size()) {
  97. case 0:
  98. return null;
  99. case 1:
  100. return (U) GwtReflectionUtils.callPrivateMethod(owner,
  101. compatibleFactories.get(0));
  102. default:
  103. throw new GwtTestUiBinderException("Duplicate factory in class '"
  104. + owner.getClass().getName() + " for type '" + clazz.getName()
  105. + "'");
  106. }
  107. }
  108. private static <U> U getProvidedUiField(Class<U> clazz, Object owner) {
  109. Map<Field, UiField> map = GwtReflectionUtils.getAnnotatedField(
  110. owner.getClass(), UiField.class);
  111. for (Map.Entry<Field, UiField> entry : map.entrySet()) {
  112. if (entry.getKey().getType() == clazz && entry.getValue().provided()) {
  113. Object providedObject = GwtReflectionUtils.getPrivateFieldValue(owner,
  114. entry.getKey());
  115. if (providedObject == null) {
  116. throw new GwtTestUiBinderException(
  117. "The UiField(provided=true) '"
  118. + entry.getKey().getDeclaringClass().getSimpleName()
  119. + "."
  120. + entry.getKey().getName()
  121. + "' has not been initialized before calling 'UiBinder.createAndBind(..)' method");
  122. }
  123. return (U) providedObject;
  124. }
  125. }
  126. return null;
  127. }
  128. private static <U> U instanciate(Constructor<U> cons, List<Object> args) {
  129. try {
  130. return GwtReflectionUtils.instantiateClass(cons, args.toArray());
  131. } catch (Exception e) {
  132. StringBuilder sb = new StringBuilder();
  133. sb.append("Error while calling @UiConstructor 'new ").append(
  134. cons.getDeclaringClass().getSimpleName()).append("(");
  135. for (Object arg : args) {
  136. sb.append("\"" + arg.toString() + "\"");
  137. sb.append(", ");
  138. }
  139. if (args.size() > 0) {
  140. sb.delete(sb.length() - 2, sb.length() - 1);
  141. }
  142. sb.append(");'");
  143. throw new GwtTestUiBinderException(sb.toString(), e);
  144. }
  145. }
  146. private static boolean matchs(Constructor<?> cons, List<Object> args) {
  147. Class<?>[] paramTypes = cons.getParameterTypes();
  148. if (paramTypes.length != args.size()) {
  149. return false;
  150. }
  151. for (int i = 0; i < args.size(); i++) {
  152. if (!paramTypes[i].isInstance(args.get(i))) {
  153. return false;
  154. }
  155. }
  156. return true;
  157. }
  158. }