diff --git a/handlebars/src/main/java/com/github/jknack/handlebars/ValueResolver.java b/handlebars/src/main/java/com/github/jknack/handlebars/ValueResolver.java index 156d98f12..4009209d1 100644 --- a/handlebars/src/main/java/com/github/jknack/handlebars/ValueResolver.java +++ b/handlebars/src/main/java/com/github/jknack/handlebars/ValueResolver.java @@ -26,7 +26,7 @@ import com.github.jknack.handlebars.context.JavaBeanValueResolver; import com.github.jknack.handlebars.context.MapValueResolver; -import com.github.jknack.handlebars.context.MethodValueResolver; +import com.github.jknack.handlebars.context.RecordValueResolver; /** * A hook interface for resolving values from the {@link Context context stack}. @@ -79,15 +79,15 @@ public interface ValueResolver { * * - {@link MapValueResolver} * - {@link JavaBeanValueResolver} - * - {@link MethodValueResolver}. On Java 14 or higher. + * - {@link RecordValueResolver}. * * @return Immutable list of value resolvers. */ static List defaultValueResolvers() { - if (Handlebars.Utils.javaVersion14) { - return unmodifiableList(asList(MapValueResolver.INSTANCE, - JavaBeanValueResolver.INSTANCE, MethodValueResolver.INSTANCE)); - } - return unmodifiableList(asList(MapValueResolver.INSTANCE, JavaBeanValueResolver.INSTANCE)); + return unmodifiableList( + asList( + MapValueResolver.INSTANCE, + JavaBeanValueResolver.INSTANCE, + RecordValueResolver.INSTANCE)); } } diff --git a/handlebars/src/main/java/com/github/jknack/handlebars/context/MemberValueResolver.java b/handlebars/src/main/java/com/github/jknack/handlebars/context/MemberValueResolver.java index 1ec5c2dd0..5e28cb58d 100644 --- a/handlebars/src/main/java/com/github/jknack/handlebars/context/MemberValueResolver.java +++ b/handlebars/src/main/java/com/github/jknack/handlebars/context/MemberValueResolver.java @@ -50,6 +50,9 @@ public abstract class MemberValueResolver implements ValueReso @Override public final Object resolve(final Object context, final String name) { + if (!matches(context)) { + return UNRESOLVED; + } Class key = context.getClass(); Map mcache = cache(key); M member = mcache.get(name); @@ -122,6 +125,16 @@ protected boolean isUseSetAccessible(final M member) { */ protected abstract Object invokeMember(M member, Object context); + /** + * True, if the context is worth examing by this resolver. + * + * @param context The context object. + * @return True, if the context is suitable. + */ + protected boolean matches(final Object context) { + return true; + } + /** * True, if the member matches the one we look for. * diff --git a/handlebars/src/main/java/com/github/jknack/handlebars/context/RecordValueResolver.java b/handlebars/src/main/java/com/github/jknack/handlebars/context/RecordValueResolver.java new file mode 100644 index 000000000..7e1aac731 --- /dev/null +++ b/handlebars/src/main/java/com/github/jknack/handlebars/context/RecordValueResolver.java @@ -0,0 +1,24 @@ +package com.github.jknack.handlebars.context; + +/** + * A resolver for Record types. + * + * This resolver is safe to use in JDKs that do not support records yet. + * + * @author agentgt + * + */ +public class RecordValueResolver extends MethodValueResolver { + + /** + * The default instance. + */ + public static final RecordValueResolver INSTANCE = new RecordValueResolver(); + + @Override + protected boolean matches(final Object context) { + Class superClass = context.getClass().getSuperclass(); + return superClass != null && superClass.getName().equals("java.lang.Record"); + } + +}