Skip to content

Commit beee81a

Browse files
committed
Java 14 Record is not supported fix #826
- Remove static array with default resolvers. Now it is a list - Added ValueResolver.defaultResolvers. It adds MethodValueResolver on Java14+
1 parent c42e403 commit beee81a

7 files changed

Lines changed: 72 additions & 33 deletions

File tree

handlebars-springmvc/src/main/java/com/github/jknack/handlebars/springmvc/HandlebarsViewResolver.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package com.github.jknack.handlebars.springmvc;
1919

20+
import static com.github.jknack.handlebars.ValueResolver.defaultValueResolvers;
2021
import static java.util.Objects.requireNonNull;
2122

2223
import java.io.File;
@@ -34,6 +35,8 @@
3435
import java.util.Map.Entry;
3536
import java.util.ResourceBundle;
3637
import java.util.Set;
38+
import java.util.stream.Collectors;
39+
import java.util.stream.Stream;
3740

3841
import org.springframework.beans.factory.InitializingBean;
3942
import org.springframework.context.ApplicationContext;
@@ -79,7 +82,7 @@ public class HandlebarsViewResolver extends AbstractTemplateViewResolver
7982
/**
8083
* The value's resolvers.
8184
*/
82-
private ValueResolver[] valueResolvers = ValueResolver.VALUE_RESOLVERS;
85+
private List<ValueResolver> valueResolvers = new ArrayList<>(defaultValueResolvers());
8386

8487
/**
8588
* Fail on missing file. Default is: true.
@@ -197,7 +200,7 @@ protected AbstractUrlBasedView configure(final HandlebarsView view)
197200
// Compile the template.
198201
try {
199202
view.setTemplate(handlebars.compile(url));
200-
view.setValueResolver(valueResolvers);
203+
view.setValueResolver(valueResolvers.toArray(new ValueResolver[0]));
201204
} catch (IOException ex) {
202205
if (failOnMissingFile) {
203206
throw ex;
@@ -331,7 +334,7 @@ public Handlebars getHandlebars() {
331334
/**
332335
* @return The array of resolvers.
333336
*/
334-
protected ValueResolver[] getValueResolvers() {
337+
protected List<ValueResolver> getValueResolvers() {
335338
return this.valueResolvers;
336339
}
337340

@@ -341,8 +344,10 @@ protected ValueResolver[] getValueResolvers() {
341344
* @param valueResolvers The value resolvers. Required.
342345
*/
343346
public void setValueResolvers(final ValueResolver... valueResolvers) {
344-
this.valueResolvers = requireNonNull(valueResolvers,
347+
requireNonNull(valueResolvers,
345348
"At least one value-resolver must be present.");
349+
this.valueResolvers = Stream.of(valueResolvers)
350+
.collect(Collectors.toList());
346351
}
347352

348353
/**

handlebars/src/main/java/com/github/jknack/handlebars/Context.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Map;
3030
import java.util.Map.Entry;
3131
import java.util.Set;
32+
import java.util.stream.Collectors;
3233
import java.util.stream.Stream;
3334

3435
import com.github.jknack.handlebars.context.MapValueResolver;
@@ -181,22 +182,22 @@ private static class CompositeValueResolver implements ValueResolver {
181182
/**
182183
* The internal value resolvers.
183184
*/
184-
private ValueResolver[] resolvers;
185+
private List<ValueResolver> resolvers;
185186

186187
/**
187188
* Creates a new {@link CompositeValueResolver}.
188189
*
189190
* @param resolvers The value resolvers.
190191
*/
191-
CompositeValueResolver(final ValueResolver... resolvers) {
192+
CompositeValueResolver(final List<ValueResolver> resolvers) {
192193
this.resolvers = resolvers;
193194
}
194195

195196
@Override
196197
public Object resolve(final Object context, final String name) {
197198
int i = 0;
198-
while (i < resolvers.length) {
199-
Object value = resolvers[i].resolve(context, name);
199+
while (i < resolvers.size()) {
200+
Object value = resolvers.get(i).resolve(context, name);
200201
if (value != UNRESOLVED) {
201202
return value == null ? NULL : value;
202203
}
@@ -208,8 +209,8 @@ public Object resolve(final Object context, final String name) {
208209
@Override
209210
public Object resolve(final Object context) {
210211
int i = 0;
211-
while (i < resolvers.length) {
212-
Object value = resolvers[i].resolve(context);
212+
while (i < resolvers.size()) {
213+
Object value = resolvers.get(i).resolve(context);
213214
if (value != UNRESOLVED) {
214215
return value == null ? NULL : value;
215216
}
@@ -258,7 +259,7 @@ private Builder(final Context parent, final Object model) {
258259
*/
259260
private Builder(final Object model) {
260261
context = Context.root(model);
261-
context.setResolver(new CompositeValueResolver(ValueResolver.VALUE_RESOLVERS));
262+
context.setResolver(new CompositeValueResolver(ValueResolver.defaultValueResolvers()));
262263
}
263264

264265
/**
@@ -294,30 +295,29 @@ public Builder resolver(final ValueResolver... resolvers) {
294295
notEmpty(resolvers, "At least one value-resolver must be present.");
295296
boolean mapResolver = Stream.of(resolvers).anyMatch(MapValueResolver.class::isInstance);
296297
if (!mapResolver) {
297-
ValueResolver[] safeResolvers = new ValueResolver[resolvers.length + 1];
298-
System.arraycopy(resolvers, 0, safeResolvers, 0, resolvers.length);
299-
safeResolvers[safeResolvers.length - 1] = MapValueResolver.INSTANCE;
300-
context.setResolver(new CompositeValueResolver(safeResolvers));
298+
context.setResolver(new CompositeValueResolver(
299+
Stream.concat(Stream.of(resolvers), Stream.of(MapValueResolver.INSTANCE))
300+
.collect(Collectors.toList())
301+
));
301302
} else {
302-
context.setResolver(new CompositeValueResolver(resolvers));
303+
context.setResolver(new CompositeValueResolver(Arrays.asList(resolvers)));
303304
}
304305
return this;
305306
}
306307

307308
/**
308309
* Add one or more value resolver to the defaults defined by
309-
* {@link ValueResolver#VALUE_RESOLVERS}.
310+
* {@link ValueResolver#defaultValueResolvers()}.
310311
*
311312
* @param resolvers The value resolvers. Required.
312313
* @return This builder.
313314
*/
314315
public Builder push(final ValueResolver... resolvers) {
315316
notEmpty(resolvers, "At least one value-resolver must be present.");
316317
List<ValueResolver> merged = new ArrayList<>();
317-
merged.addAll(Arrays.asList(ValueResolver.VALUE_RESOLVERS));
318-
merged.addAll(Arrays.asList(resolvers));
319-
context.setResolver(
320-
new CompositeValueResolver(merged.toArray(new ValueResolver[merged.size()])));
318+
merged.addAll(ValueResolver.defaultValueResolvers());
319+
Stream.of(resolvers).forEach(merged::add);
320+
context.setResolver(new CompositeValueResolver(merged));
321321
return this;
322322
}
323323

handlebars/src/main/java/com/github/jknack/handlebars/Handlebars.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,15 @@ public boolean equals(final Object obj) {
176176
*/
177177
public static class Utils {
178178

179+
/** Java 14. */
180+
private static final int JAVA_14 = 14;
181+
179182
/** Current Java version: 8, 11, 15, etc. */
180183
public static final int javaVersion = javaVersion();
181184

185+
/** True when running on Java 14 or higher. */
186+
public static final boolean javaVersion14 = javaVersion() >= JAVA_14;
187+
182188
/** Prefix for Java version: 1.8 (mostly). */
183189
private static final String VERSION_PREFIX = "1.";
184190

handlebars/src/main/java/com/github/jknack/handlebars/ValueResolver.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@
1717
*/
1818
package com.github.jknack.handlebars;
1919

20+
import static java.util.Arrays.asList;
21+
import static java.util.Collections.unmodifiableList;
22+
23+
import java.util.List;
2024
import java.util.Map.Entry;
2125
import java.util.Set;
2226

2327
import com.github.jknack.handlebars.context.JavaBeanValueResolver;
2428
import com.github.jknack.handlebars.context.MapValueResolver;
29+
import com.github.jknack.handlebars.context.MethodValueResolver;
2530

2631
/**
2732
* A hook interface for resolving values from the {@link Context context stack}.
@@ -31,12 +36,6 @@
3136
*/
3237
public interface ValueResolver {
3338

34-
/**
35-
* The default value resolvers.
36-
*/
37-
ValueResolver[] VALUE_RESOLVERS = {MapValueResolver.INSTANCE,
38-
JavaBeanValueResolver.INSTANCE };
39-
4039
/**
4140
* A mark object.
4241
*/
@@ -67,12 +66,28 @@ public interface ValueResolver {
6766
*/
6867
Object resolve(Object context);
6968

70-
7169
/**
7270
* List all the properties and their values for the given object.
7371
*
7472
* @param context The context object. Not null.
7573
* @return All the properties and their values for the given object.
7674
*/
7775
Set<Entry<String, Object>> propertySet(Object context);
76+
77+
/**
78+
* Default value resolvers. Including:
79+
*
80+
* - {@link MapValueResolver}
81+
* - {@link JavaBeanValueResolver}
82+
* - {@link MethodValueResolver}. On Java 14 or higher.
83+
*
84+
* @return Immutable list of value resolvers.
85+
*/
86+
static List<ValueResolver> defaultValueResolvers() {
87+
if (Handlebars.Utils.javaVersion14) {
88+
return unmodifiableList(asList(MapValueResolver.INSTANCE,
89+
JavaBeanValueResolver.INSTANCE, MethodValueResolver.INSTANCE));
90+
}
91+
return unmodifiableList(asList(MapValueResolver.INSTANCE, JavaBeanValueResolver.INSTANCE));
92+
}
7893
}

handlebars/src/main/java/com/github/jknack/handlebars/internal/BaseTemplate.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@
5757
*/
5858
abstract class BaseTemplate implements Template {
5959

60-
/** Java 15. */
61-
private static final int JAVA_15 = 15;
62-
6360
/**
6461
* The handlebars object. Required.
6562
*/
@@ -268,7 +265,7 @@ private boolean isDefault(final Method method) {
268265

269266
private Object invokeDefaultMethod(final Method method, final Class<?> lookupClass,
270267
final Object proxy, final Object... args) throws Throwable {
271-
if (Handlebars.Utils.javaVersion >= JAVA_15) {
268+
if (Handlebars.Utils.javaVersion14) {
272269
MethodType methodType = MethodType.methodType(method.getReturnType(),
273270
method.getParameterTypes());
274271
return MethodHandles.lookup()

handlebars/src/test/java/com/github/jknack/handlebars/EachKeyTest.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
import org.junit.Ignore;
2727
import org.junit.Test;
2828

29+
import com.github.jknack.handlebars.context.JavaBeanValueResolver;
30+
import com.github.jknack.handlebars.context.MapValueResolver;
31+
2932
public class EachKeyTest extends AbstractTest {
3033

3134
public static class Blog {
@@ -48,6 +51,12 @@ public String getBody() {
4851
}
4952
}
5053

54+
@Override protected Object configureContext(Object context) {
55+
return Context.newBuilder(context)
56+
.resolver(MapValueResolver.INSTANCE, JavaBeanValueResolver.INSTANCE)
57+
.build();
58+
}
59+
5160
@Ignore
5261
public void eachKeyWithString() throws IOException {
5362
String result = compile("{{#each this}}{{@key}} {{/each}}").apply("String");
@@ -65,7 +74,7 @@ public void eachKeyWithInt() throws IOException {
6574
@Test
6675
public void eachKeyWithJavaBean() throws IOException {
6776
Blog blog = new Blog("Handlebars.java", "...");
68-
String result = compile("{{#each this}}{{@key}}: {{this}} {{/each}}").apply(blog);
77+
String result = compile("{{#each this}}{{@key}}: {{this}} {{/each}}").apply(configureContext(blog));
6978

7079
String expected1 = "body: ... title: Handlebars.java ";
7180
String expected2 = "title: Handlebars.java body: ... ";

handlebars/src/test/java/handlebarsjs/spec/BlockHelperMissingTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@
1515
import com.github.jknack.handlebars.HelperRegistry;
1616
import com.github.jknack.handlebars.Options;
1717
import com.github.jknack.handlebars.Template;
18+
import com.github.jknack.handlebars.context.JavaBeanValueResolver;
1819

1920
public class BlockHelperMissingTest extends AbstractTest {
2021

22+
@Override protected Object configureContext(Object context) {
23+
return Context.newBuilder(context)
24+
.resolver(JavaBeanValueResolver.INSTANCE)
25+
.build();
26+
}
27+
2128
@Test
2229
public void ifContextIsNotFoundHelperMissingIsUsed() throws IOException {
2330
String string = "{{hello}} {{link_to world}}";

0 commit comments

Comments
 (0)