2525import com .google .gwt .core .ext .typeinfo .TypeOracleException ;
2626import com .google .gwt .i18n .rebind .AbstractResource .ResourceList ;
2727import com .google .gwt .i18n .shared .GwtLocale ;
28- import com .google .gwt .user . rebind . AbstractMethodCreator ;
28+ import com .google .gwt .thirdparty . guava . common . collect . Lists ;
2929import com .google .gwt .user .rebind .SourceWriter ;
3030
31+ import java .text .MessageFormat ;
32+ import java .util .ArrayList ;
33+ import java .util .Collections ;
3134import java .util .HashMap ;
35+ import java .util .Iterator ;
36+ import java .util .List ;
3237import java .util .Map ;
38+ import java .util .Map .Entry ;
3339
3440class ConstantsWithLookupImplCreator extends ConstantsImplCreator {
41+
42+ /**
43+ * Used partition size if no one is specified.
44+ *
45+ * Used in constructor without a partition size.
46+ */
47+ private static final int DEFAULT_PARTITIONS_SIZE = 500 ;
48+
3549 final JMethod [] allInterfaceMethods ;
3650
37- private final Map <String , AbstractMethodCreator > namesToMethodCreators = new HashMap <String , AbstractMethodCreator >();
51+ private final Map <String , LookupMethodCreator > namesToMethodCreators = new HashMap <>();
52+
53+ private final Map <JMethod , List <List <JMethod >>> neededPartitionLookups = new HashMap <>();
54+
55+ private final int partitionsSize ;
3856
3957 /**
40- * Constructor for <code>ConstantsWithLookupImplCreator</code>.
58+ * Constructor for <code>ConstantsWithLookupImplCreator</code>. The default partition size of
59+ * {@value #DEFAULT_PARTITIONS_SIZE} is used.
4160 *
4261 * @param logger logger to print errors
4362 * @param writer <code>Writer</code> to print to
4463 * @param localizableClass class/interface to conform to
4564 * @param resourceList resource bundle used to generate the class
4665 * @param oracle types
4766 * @throws UnableToCompleteException
67+ *
68+ * @see LookupMethodCreator#DEFAULT_PARTITIONS_SIZE
4869 */
4970 ConstantsWithLookupImplCreator (TreeLogger logger , SourceWriter writer ,
5071 JClassType localizableClass , ResourceList resourceList , TypeOracle oracle )
5172 throws UnableToCompleteException {
73+ this (logger , writer , localizableClass , resourceList , oracle , DEFAULT_PARTITIONS_SIZE );
74+ }
75+
76+ /**
77+ * Constructor for <code>ConstantsWithLookupImplCreator</code>.
78+ *
79+ * @param logger logger to print errors
80+ * @param writer <code>Writer</code> to print to
81+ * @param localizableClass class/interface to conform to
82+ * @param resourceList resource bundle used to generate the class
83+ * @param oracle types
84+ * @throws UnableToCompleteException
85+ */
86+ ConstantsWithLookupImplCreator (TreeLogger logger , SourceWriter writer ,
87+ JClassType localizableClass , ResourceList resourceList , TypeOracle oracle ,
88+ int partitionsSize ) throws UnableToCompleteException {
5289 super (logger , writer , localizableClass , resourceList , oracle );
90+ this .partitionsSize = partitionsSize ;
5391 try {
5492
5593 // Boolean
@@ -63,7 +101,9 @@ public void printReturnTarget() {
63101
64102 @ Override
65103 public String returnTemplate () {
66- return "boolean answer = {0}();\n cache.put(\" {0}\" ,new Boolean(answer));\n return answer;" ;
104+ return "boolean answer = {0}();\n "
105+ + "cache.put(\" {0}\" ,new Boolean(answer));\n "
106+ + "return answer;" ;
67107 }
68108 };
69109 namesToMethodCreators .put ("getBoolean" , booleanMethod );
@@ -79,7 +119,9 @@ public void printReturnTarget() {
79119
80120 @ Override
81121 public String returnTemplate () {
82- return "double answer = {0}();\n cache.put(\" {0}\" ,new Double(answer));\n return answer;" ;
122+ return "double answer = {0}();\n "
123+ + "cache.put(\" {0}\" ,new Double(answer));\n "
124+ + "return answer;" ;
83125 }
84126 };
85127 namesToMethodCreators .put ("getDouble" , doubleMethod );
@@ -94,7 +136,9 @@ public void printReturnTarget() {
94136
95137 @ Override
96138 public String returnTemplate () {
97- return "int answer = {0}();\n cache.put(\" {0}\" ,new Integer(answer));\n return answer;" ;
139+ return "int answer = {0}();\n "
140+ + "cache.put(\" {0}\" ,new Integer(answer));\n "
141+ + "return answer;" ;
98142 }
99143 };
100144
@@ -105,7 +149,9 @@ public String returnTemplate() {
105149 LookupMethodCreator floatMethod = new LookupMethodCreator (this , floatType ) {
106150 @ Override
107151 public String returnTemplate () {
108- String val = "float answer = {0}();\n cache.put(\" {0}\" , new Float(answer));\n return answer;" ;
152+ String val = "float answer = {0}();\n "
153+ + "cache.put(\" {0}\" , new Float(answer));\n "
154+ + "return answer;" ;
109155 return val ;
110156 }
111157
@@ -132,7 +178,9 @@ public String getReturnTypeName() {
132178 stringType ) {
133179 @ Override
134180 public String returnTemplate () {
135- return "String answer = {0}();\n cache.put(\" {0}\" ,answer);\n return answer;" ;
181+ return "String answer = {0}();\n "
182+ + "cache.put(\" {0}\" ,answer);\n "
183+ + "return answer;" ;
136184 }
137185 };
138186 namesToMethodCreators .put ("getString" , stringMethod );
@@ -149,6 +197,12 @@ public String returnTemplate() {
149197 }
150198 }
151199
200+ @ Override
201+ protected void classEpilog () {
202+ createNeededPartitionLookups ();
203+ super .classEpilog ();
204+ }
205+
152206 /**
153207 * Create the method body associated with the given method. Arguments are
154208 * arg0...argN.
@@ -159,16 +213,78 @@ protected void emitMethodBody(TreeLogger logger, JMethod method,
159213 checkMethod (logger , method );
160214 if (method .getParameters ().length == 1 ) {
161215 String name = method .getName ();
162- AbstractMethodCreator c = namesToMethodCreators . get (name );
216+ LookupMethodCreator c = getLookupMethodCreator (name );
163217 if (c != null ) {
164- c . createMethodFor ( logger , method , name , null , locale );
218+ createMethodWithPartitionCheckFor ( c , method );
165219 return ;
166220 }
167221 }
168222 // fall through
169223 super .emitMethodBody (logger , method , locale );
170224 }
171225
226+ void addNeededPartitionLookups (JMethod targetMethod ,
227+ List <List <JMethod >> methodToCreatePartitionLookups ) {
228+ neededPartitionLookups .put (targetMethod , methodToCreatePartitionLookups );
229+ }
230+
231+ void createMethodWithPartitionCheckFor (LookupMethodCreator methodCreator , JMethod targetMethod ) {
232+ List <List <JMethod >> methodPartitions = findMethodsToCreateWithPartitionSize (targetMethod ,
233+ methodCreator .getReturnType ());
234+
235+ String nextPartitionMethod = null ;
236+ final List <List <JMethod >> methodToCreatePartitionLookups ;
237+ final List <JMethod > methodsToCreate ;
238+ if (methodPartitions .size () > 1 ) {
239+ nextPartitionMethod = createPartitionMethodName (targetMethod , 0 );
240+ methodsToCreate = methodPartitions .get (0 );
241+ methodToCreatePartitionLookups = methodPartitions .subList (1 , methodPartitions .size ());
242+ } else {
243+ methodsToCreate = methodPartitions .isEmpty () ? Collections .<JMethod > emptyList ()
244+ : methodPartitions .get (0 );
245+ methodToCreatePartitionLookups = Collections .emptyList ();
246+ }
247+ addNeededPartitionLookups (targetMethod , methodToCreatePartitionLookups );
248+ methodCreator .createCacheLookupFor ();
249+ methodCreator .createMethodFor (targetMethod , methodsToCreate , nextPartitionMethod );
250+ }
251+
252+ String createPartitionMethodName (JMethod targetMethod , int partitionIndex ) {
253+ final String templatePartitionMethodName = "{0}FromPartition{1}" ;
254+ return MessageFormat .format (templatePartitionMethodName , new Object [] {
255+ targetMethod .getName (), partitionIndex });
256+ }
257+
258+ List <JMethod > findAllMethodsToCreate (JMethod targetMethod , JType methodReturnType ) {
259+ JMethod [] allMethods = allInterfaceMethods ;
260+ JType erasedType = methodReturnType .getErasedType ();
261+ List <JMethod > methodsToCreate = new ArrayList <>();
262+ for (JMethod methodToCheck : allMethods ) {
263+ if (methodToCheck .getReturnType ().getErasedType ().equals (erasedType )
264+ && methodToCheck != targetMethod ) {
265+ methodsToCreate .add (methodToCheck );
266+ }
267+ }
268+ return methodsToCreate ;
269+ }
270+
271+ List <List <JMethod >> findMethodsToCreateWithPartitionSize (JMethod targetMethod ,
272+ JType methodReturnType ) {
273+ List <JMethod > allMethodsToCreate = findAllMethodsToCreate (targetMethod , methodReturnType );
274+ return Lists .partition (allMethodsToCreate , partitionsSize );
275+ }
276+
277+ LookupMethodCreator getLookupMethodCreator (String name ) {
278+ return namesToMethodCreators .get (name );
279+ }
280+
281+ /**
282+ * Visible for testing only.
283+ */
284+ Map <JMethod , List <List <JMethod >>> getNeededPartitionLookups () {
285+ return neededPartitionLookups ;
286+ }
287+
172288 /**
173289 * Checks that the method has the right structure to implement
174290 * <code>Constant</code>.
@@ -177,7 +293,7 @@ protected void emitMethodBody(TreeLogger logger, JMethod method,
177293 */
178294 private void checkMethod (TreeLogger logger , JMethod method )
179295 throws UnableToCompleteException {
180- if (namesToMethodCreators . get (method .getName ()) != null ) {
296+ if (getLookupMethodCreator (method .getName ()) != null ) {
181297 JParameter [] params = method .getParameters ();
182298 // user may have specified a method named getInt/etc with no parameters
183299 // this isn't a conflict, so treat them like any other Constant methods
@@ -195,4 +311,26 @@ private void checkMethod(TreeLogger logger, JMethod method)
195311 checkConstantMethod (logger , method );
196312 }
197313 }
314+
315+ private void createNeededPartitionLookups () {
316+ for (Entry <JMethod , List <List <JMethod >>> neededPartitionLookup :
317+ neededPartitionLookups .entrySet ()) {
318+ JMethod targetMethod = neededPartitionLookup .getKey ();
319+ LookupMethodCreator lookupMethodCreator = getLookupMethodCreator (targetMethod .getName ());
320+ List <List <JMethod >> methodForPartitionLookups = neededPartitionLookup .getValue ();
321+ int partitionStartIndex = 0 ;
322+ Iterator <List <JMethod >> neededPartitionIterator = methodForPartitionLookups .iterator ();
323+ while (neededPartitionIterator .hasNext ()) {
324+ String currentPartitionLookupMethodName = createPartitionMethodName (targetMethod ,
325+ partitionStartIndex ++);
326+ List <JMethod > methodsToCreate = neededPartitionIterator .next ();
327+ String nextPartitionMethod = null ;
328+ if (neededPartitionIterator .hasNext ()) {
329+ nextPartitionMethod = createPartitionMethodName (targetMethod , partitionStartIndex );
330+ }
331+ lookupMethodCreator .createPartitionLookup (currentPartitionLookupMethodName , targetMethod ,
332+ methodsToCreate , nextPartitionMethod );
333+ }
334+ }
335+ }
198336}
0 commit comments