Skip to content

Commit 39c63c0

Browse files
author
JimLaskey
committed
Clean up new StringTemplate creation
Centralized StringTemplate creation in StringTemplateImplFactory. Added consistent defensive copying of lists. Changed List<Object> to List<?> on StringTemplate.interpolate and StringTemplate.of.
1 parent 1af7dc1 commit 39c63c0

File tree

6 files changed

+137
-86
lines changed

6 files changed

+137
-86
lines changed

src/java.base/share/classes/java/lang/runtime/TemplateRuntime.java

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,9 @@
3333
import java.lang.template.ProcessorLinkage;
3434
import java.lang.template.StringTemplate;
3535
import java.lang.template.ValidatingProcessor;
36-
import java.util.List;
37-
import java.util.Objects;
36+
import java.util.*;
3837

3938
import jdk.internal.access.JavaTemplateAccess;
40-
import jdk.internal.access.JavaUtilCollectionAccess;
4139
import jdk.internal.access.SharedSecrets;
4240
import jdk.internal.javac.PreviewFeature;
4341

@@ -62,7 +60,6 @@
6260
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
6361
public final class TemplateRuntime {
6462
private static final JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess();
65-
private static final JavaUtilCollectionAccess JUCA = SharedSecrets.getJavaUtilCollectionAccess();
6663

6764
/**
6865
* {@link MethodHandle} to {@link TemplateRuntime#defaultProcess}.
@@ -202,8 +199,8 @@ private static Object defaultProcess(
202199
ValidatingProcessor<?, ?> processor,
203200
Object[] values
204201
) throws Throwable {
205-
return processor.process(
206-
StringTemplate.of(fragments, JUCA.listFromTrustedArrayNullsAllowed(values)));
202+
List<Object> asList = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(values)));
203+
return processor.process(StringTemplate.of(fragments, asList));
207204
}
208205

209206
/**
@@ -221,22 +218,7 @@ private static MethodHandle defaultProcessMethodHandle(
221218
return mh.asCollector(Object[].class, type.parameterCount()).asType(type);
222219
}
223220

224-
/**
225-
* A {@link StringTemplate} where number of value slots exceeds
226-
* {@link java.lang.invoke.StringConcatFactory#MAX_INDY_CONCAT_ARG_SLOTS}.
227-
*
228-
* @param fragments immutable list of string fragments from string template
229-
* @param values immutable list of expression values
230-
*/
231-
private record LargeStringTemplate(List<String> fragments, List<Object> values)
232-
implements StringTemplate {
233-
@Override
234-
public java.lang.String toString() {
235-
return StringTemplate.toString(this);
236-
}
237-
}
238-
239-
/**
221+
/**
240222
* Used to create a {@link StringTemplate} when number of value slots exceeds
241223
* {@link java.lang.invoke.StringConcatFactory#MAX_INDY_CONCAT_ARG_SLOTS}.
242224
*
@@ -246,8 +228,7 @@ public java.lang.String toString() {
246228
* @return new {@link StringTemplate}
247229
*/
248230
private static StringTemplate fromArrays(String[] fragments, Object[] values) {
249-
return new LargeStringTemplate(List.of(fragments),
250-
JUCA.listFromTrustedArrayNullsAllowed(values));
231+
return JTA.newStringTemplate(fragments, values);
251232
}
252233
}
253234

src/java.base/share/classes/java/lang/template/StringTemplate.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ public static String toString(StringTemplate stringTemplate) {
215215
*/
216216
public static StringTemplate of(String string) {
217217
Objects.requireNonNull(string, "string must not be null");
218-
return new TemplateSupport.SimpleStringTemplate(List.of(string), List.of());
218+
return TemplateSupport.of(List.of(string), List.of());
219219
}
220220

221221
/**
@@ -235,16 +235,14 @@ public static StringTemplate of(String string) {
235235
*
236236
* @implNote Contents of both lists are copied to construct immutable lists.
237237
*/
238-
public static StringTemplate of(List<String> fragments, List<Object> values) {
238+
public static StringTemplate of(List<String> fragments, List<?> values) {
239239
Objects.requireNonNull(fragments, "fragments must not be null");
240240
Objects.requireNonNull(values, "values must not be null");
241241
if (values.size() + 1 != fragments.size()) {
242242
throw new IllegalArgumentException(
243243
"fragments list size is not one more than values list size");
244244
}
245-
fragments = List.copyOf(fragments);
246-
values = TemplateSupport.toList(values.toArray().clone());
247-
return new TemplateSupport.SimpleStringTemplate(fragments, values);
245+
return TemplateSupport.of(fragments, values);
248246
}
249247

250248
/**
@@ -260,15 +258,15 @@ public static StringTemplate of(List<String> fragments, List<Object> values) {
260258
* than values list size
261259
* @throws NullPointerException fragments or values is null or if any of the fragments is null
262260
*/
263-
public static String interpolate(List<String> fragments, List<Object> values) {
261+
public static String interpolate(List<String> fragments, List<?> values) {
264262
Objects.requireNonNull(fragments, "fragments must not be null");
265263
Objects.requireNonNull(values, "values must not be null");
266264
int fragmentsSize = fragments.size();
267265
int valuesSize = values.size();
268266
if (fragmentsSize != valuesSize + 1) {
269267
throw new IllegalArgumentException("fragments must have one more element than values");
270268
}
271-
return TemplateSupport.interpolate(List.copyOf(fragments), TemplateSupport.toList(values.toArray()));
269+
return TemplateSupport.interpolate(fragments, values);
272270
}
273271

274272
/**
@@ -298,7 +296,7 @@ public static StringTemplate combine(StringTemplate... sts) {
298296
* }
299297
* @implNote The result of interpolation is not interned.
300298
*/
301-
public static final StringProcessor STR = TemplateSupport.basicInterpolate();
299+
public static final StringProcessor STR = StringTemplate::interpolate;
302300

303301
/**
304302
* No-op template processor. Used to highlight that non-processing of the StringTemplate

src/java.base/share/classes/java/lang/template/StringTemplateImplFactory.java

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import java.lang.invoke.MethodType;
3131
import java.lang.invoke.StringConcatException;
3232
import java.lang.invoke.StringConcatFactory;
33+
import java.util.Arrays;
34+
import java.util.Collections;
3335
import java.util.List;
3436

3537
import jdk.internal.access.JavaTemplateAccess;
@@ -64,26 +66,6 @@ final class StringTemplateImplFactory implements JavaTemplateAccess {
6466
*/
6567
private static final MethodHandle TO_LIST;
6668

67-
/**
68-
* Access to nullible form of {@code List.of}
69-
*/
70-
private static final JavaUtilCollectionAccess JUCA = SharedSecrets.getJavaUtilCollectionAccess();
71-
72-
/**
73-
* Collect nullable elements from an array into a unmodifiable list.
74-
*
75-
* @param elements elements to place in list
76-
*
77-
* @return unmodifiable list.
78-
*
79-
* @param <E> type of elements
80-
*/
81-
@SafeVarargs
82-
@SuppressWarnings({"unchecked", "varargs"})
83-
private static <E> List<E> toList(E... elements) {
84-
return JUCA.listFromTrustedArrayNullsAllowed(elements);
85-
}
86-
8769
static {
8870
try {
8971
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -109,7 +91,8 @@ private static <E> List<E> toList(E... elements) {
10991
* @return {@link MethodHandle} that can construct a {@link StringTemplateImpl} with arguments
11092
* used as values.
11193
*/
112-
public MethodHandle createStringTemplateImplMH(List<String> fragments, MethodType type) {
94+
@Override
95+
public MethodHandle createStringTemplateImplMH(List<String> fragments, MethodType type) {
11396
Carriers.CarrierElements elements = Carriers.CarrierFactory.of(type);
11497
MethodHandle[] components = elements
11598
.components()
@@ -151,4 +134,72 @@ public MethodHandle createStringTemplateImplMH(List<String> fragments, MethodTy
151134
return constructor;
152135
}
153136

137+
/**
138+
* Generic {@link StringTemplate}.
139+
*
140+
* @param fragments immutable list of string fragments from string template
141+
* @param values immutable list of expression values
142+
*/
143+
private record SimpleStringTemplate(List<String> fragments, List<Object> values)
144+
implements StringTemplate {
145+
@Override
146+
public String toString() {
147+
return StringTemplate.toString(this);
148+
}
149+
}
150+
151+
/**
152+
* Returns a new StringTemplate composed from fragments and values.
153+
*
154+
* @param fragments array of string fragments
155+
* @param values array of expression values
156+
*
157+
* @return StringTemplate composed from fragments and values
158+
*/
159+
@Override
160+
public StringTemplate newStringTemplate(String[] fragments, Object[] values) {
161+
return new SimpleStringTemplate(List.of(fragments), toList(values));
162+
}
163+
164+
/**
165+
* Returns a new StringTemplate composed from fragments and values.
166+
*
167+
* @param fragments list of string fragments
168+
* @param values array of expression values
169+
*
170+
* @return StringTemplate composed from fragments and values
171+
*/
172+
@Override
173+
public StringTemplate newStringTemplate(List<String> fragments, Object[] values) {
174+
return new SimpleStringTemplate(List.copyOf(fragments), toList(values));
175+
}
176+
177+
/**
178+
* Returns a new StringTemplate composed from fragments and values.
179+
*
180+
* @param fragments list of string fragments
181+
* @param values list of expression values
182+
*
183+
* @return StringTemplate composed from fragments and values
184+
*/
185+
@Override
186+
public StringTemplate newStringTemplate(List<String> fragments, List<?> values) {
187+
return new SimpleStringTemplate(List.copyOf(fragments), toList(values.stream().toArray()));
188+
}
189+
190+
/**
191+
* Collect nullable elements from an array into a unmodifiable list.
192+
*
193+
* @param elements elements to place in list
194+
*
195+
* @return unmodifiable list.
196+
*
197+
* @param <E> type of elements
198+
*/
199+
@SafeVarargs
200+
@SuppressWarnings({"unchecked", "varargs"})
201+
private static <E> List<E> toList(E... elements) {
202+
return Collections.unmodifiableList(Arrays.asList(elements));
203+
}
204+
154205
}

src/java.base/share/classes/java/lang/template/TemplateSupport.java

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -61,37 +61,32 @@ private TemplateSupport() {
6161
throw new AssertionError("private constructor");
6262
}
6363

64-
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
64+
static {
65+
SharedSecrets.setJavaTemplateAccess(new StringTemplateImplFactory());
66+
}
6567

66-
private static final JavaUtilCollectionAccess JUCA = SharedSecrets.getJavaUtilCollectionAccess();
68+
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
69+
private static final JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess();
6770

6871
/**
69-
* Collect nullable elements from an array into a unmodifiable list.
72+
* Returns a StringTemplate composed from fragments and values.
7073
*
71-
* @param elements elements to place in list
74+
* @implSpec The {@code fragments} list size must be one more that the
75+
* {@code values} list size.
7276
*
73-
* @return unmodifiable list.
77+
* @param fragments list of string fragments
78+
* @param values list of expression values
7479
*
75-
* @param <E> type of elements
76-
*/
77-
@SafeVarargs
78-
@SuppressWarnings({"unchecked", "varargs"})
79-
static <E> List<E> toList(E... elements) {
80-
return JUCA.listFromTrustedArrayNullsAllowed(elements);
81-
}
82-
83-
/**
84-
* Generic {@link StringTemplate}.
80+
* @return StringTemplate composed from fragments and values
81+
*
82+
* @throws IllegalArgumentException if fragments list size is not one more
83+
* than values list size
84+
* @throws NullPointerException if fragments is null or values is null or if any fragment is null.
8585
*
86-
* @param fragments immutable list of string fragments from string template
87-
* @param values immutable list of expression values
86+
* @implNote Contents of both lists are copied to construct immutable lists.
8887
*/
89-
record SimpleStringTemplate(List<String> fragments, List<Object> values)
90-
implements StringTemplate {
91-
@Override
92-
public java.lang.String toString() {
93-
return StringTemplate.toString(this);
94-
}
88+
static StringTemplate of(List<String> fragments, List<?> values) {
89+
return JTA.newStringTemplate(fragments, values);
9590
}
9691

9792
/**
@@ -103,21 +98,20 @@ public java.lang.String toString() {
10398
*
10499
* @return String interpolation of fragments and values
105100
*/
106-
static String interpolate(List<String> fragments, List<Object> values) {
101+
static String interpolate(List<String> fragments, List<?> values) {
107102
int fragmentsSize = fragments.size();
108103
int valuesSize = values.size();
109104
if (fragmentsSize == 1) {
110105
return fragments.get(0);
111106
}
112107
int size = fragmentsSize + valuesSize;
113108
String[] strings = new String[size];
114-
Iterator<String> fragmentsIter = fragments.iterator();
115-
int i = 0;
116-
for (Object value : values) {
117-
strings[i++] = fragmentsIter.next();
118-
strings[i++] = String.valueOf(value);
109+
int i = 0, j = 0;
110+
for (; j < valuesSize; j++) {
111+
strings[i++] = fragments.get(j);
112+
strings[i++] = String.valueOf(values.get(j));
119113
}
120-
strings[i++] = fragmentsIter.next();
114+
strings[i] = fragments.get(j);
121115
return JLA.join("", "", "", strings, size);
122116
}
123117

@@ -163,7 +157,7 @@ static StringTemplate combine(StringTemplate... sts) {
163157
}
164158
}
165159
combinedFragments[i] = last;
166-
return new SimpleStringTemplate(TemplateSupport.toList(combinedFragments), TemplateSupport.toList(combinedValues));
160+
return JTA.newStringTemplate(combinedFragments, combinedValues);
167161
}
168162

169163
/**

src/java.base/share/classes/jdk/internal/access/JavaTemplateAccess.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import java.lang.invoke.MethodHandle;
2929
import java.lang.invoke.MethodType;
30+
import java.lang.template.StringTemplate;
3031
import java.util.List;
3132

3233
public interface JavaTemplateAccess {
@@ -39,5 +40,29 @@ public interface JavaTemplateAccess {
3940
// @return {@link MethodHandle} that can construct a {@link StringTemplateImpl} with arguments
4041
// used as values.
4142
public MethodHandle createStringTemplateImplMH(List<String> fragments, MethodType type);
43+
44+
// Returns a new StringTemplate composed from fragments and values.
45+
//
46+
// @param fragments array of string fragments
47+
// @param values array of expression values
48+
//
49+
// @return StringTemplate composed from fragments and values
50+
public StringTemplate newStringTemplate(String[] fragments, Object[] values);
51+
52+
// Returns a new StringTemplate composed from fragments and values.
53+
//
54+
// @param fragments list of string fragments
55+
// @param values array of expression values
56+
//
57+
// @return StringTemplate composed from fragments and values
58+
public StringTemplate newStringTemplate(List<String> fragments, Object[] values);
59+
60+
// Returns a new StringTemplate composed from fragments and values.
61+
//
62+
// @param fragments list of string fragments
63+
// @param values list of expression values
64+
//
65+
// @return StringTemplate composed from fragments and values
66+
public StringTemplate newStringTemplate(List<String> fragments, List<?> values);
4267
}
4368

src/java.base/share/classes/jdk/internal/access/SharedSecrets.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,10 @@ public static void setJavaTemplateAccess(JavaTemplateAccess jta) {
525525
public static JavaTemplateAccess getJavaTemplateAccess() {
526526
var access = javaTemplateAccess;
527527
if (access == null) {
528-
ensureClassInitialized(StringTemplate.class);
529-
access = javaTemplateAccess;
528+
try {
529+
Class.forName("java.lang.template.TemplateSupport", true, null);
530+
access = javaTemplateAccess;
531+
} catch (ClassNotFoundException e) {}
530532
}
531533
return access;
532534
}

0 commit comments

Comments
 (0)