[ 
https://issues.apache.org/jira/browse/FREEMARKER-24?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15869554#comment-15869554
 ] 

Aron Wieck edited comment on FREEMARKER-24 at 2/16/17 8:52 AM:
---------------------------------------------------------------

Currently, ClassIntrospector discovers methods using 
beanInfo.getPropertyDescriptors();

{code:java}
        Map<String, PropertyDescriptor> propertyDescriptors = new 
LinkedHashMap<>();

        PropertyDescriptor[] pda = beanInfo.getPropertyDescriptors();
        if (pda != null)
            for (PropertyDescriptor pd : pda)
                propertyDescriptors.put(pd.getName(), pd);
{code}


A quick and dirty fix would be to manually add default Methods:

{code:java}

        Map<String, Method> getters = new HashMap<>();
        Map<String, Method> setters = new HashMap<>();
        Set<String> props = new LinkedHashSet<>();
        for (Method method : clazz.getMethods())
            if (method.isDefault()) {
                final String methodName = method.getName();

                boolean getter = true;
                String name = null;

                if (methodName.startsWith("is") && methodName.length() > 2) {
                    name = Introspector.decapitalize(methodName.substring(2));
                    getter = true;
                } else if (methodName.startsWith("get") && methodName.length() 
> 3) {
                    name = Introspector.decapitalize(methodName.substring(3));
                    getter = true;
                } else if (methodName.startsWith("set") && methodName.length() 
> 3) {
                    name = Introspector.decapitalize(methodName.substring(3));
                    getter = false;
                }

                if (name != null) {
                    props.add(name);
                    if (getter)
                        getters.put(name, method);
                    else
                        setters.put(name, method);
                }
            }
        for (String prop : props) {
            PropertyDescriptor orig = propertyDescriptors.get(prop);
            Method readMethod = orig != null && orig.getReadMethod() != null ? 
orig.getReadMethod() : getters.get(prop);
            Method writeMethod = orig != null && orig.getWriteMethod() != null 
? orig.getWriteMethod() : setters.get(prop);
            propertyDescriptors.put(prop, new PropertyDescriptor(prop, 
readMethod, writeMethod));

        }
{code}



was (Author: eunice_):
Currently, ClassIntrospector discovers methods using 
beanInfo.getPropertyDescriptors();

{code:java}
        Map<String, PropertyDescriptor> propertyDescriptors = new 
LinkedHashMap<>();

        PropertyDescriptor[] pda = beanInfo.getPropertyDescriptors();
        if (pda != null)
            for (PropertyDescriptor pd : pda)
                propertyDescriptors.put(pd.getName(), pd);
{code}


A quick and dirty fix would be to manually add default Methods:

{code:java}

        Map<String, Method> getters = new HashMap<>();
        Map<String, Method> setters = new HashMap<>();
        Set<String> props = new LinkedHashSet<>();
        for (Method method : clazz.getMethods())
            if (method.isDefault()) {
                final String methodName = method.getName();

                boolean getter = true;
                String name = null;

                if (methodName.startsWith("is") && methodName.length() > 2) {
                    name = Introspector.decapitalize(methodName.substring(2));
                    getter = true;
                } else if (methodName.startsWith("get") && methodName.length() 
> 3) {
                    name = Introspector.decapitalize(methodName.substring(3));
                    getter = true;
                } else if (methodName.startsWith("set") && methodName.length() 
> 3) {
                    name = Introspector.decapitalize(methodName.substring(3));
                    getter = false;
                }

                if (name != null) {
                    props.add(name);
                    if (getter)
                        getters.put(name, method);
                    else
                        setters.put(name, method);
                }
            }
        for (String prop : props) {
            //System.out.println("Adding default property to " + 
clazz.getName() + " " + prop);
            PropertyDescriptor orig = propertyDescriptors.get(prop);
            Method readMethod = orig != null && orig.getReadMethod() != null ? 
orig.getReadMethod() : getters.get(prop);
            Method writeMethod = orig != null && orig.getWriteMethod() != null 
? orig.getWriteMethod() : setters.get(prop);
            propertyDescriptors.put(prop, new PropertyDescriptor(prop, 
readMethod, writeMethod));

        }
{code}


> Support of default methods in object model
> ------------------------------------------
>
>                 Key: FREEMARKER-24
>                 URL: https://issues.apache.org/jira/browse/FREEMARKER-24
>             Project: Apache Freemarker
>          Issue Type: Improvement
>          Components: engine
>    Affects Versions: 2.3.24-incubating
>            Reporter: Emmanuel Keller
>            Priority: Minor
>
> The default object method model currently does not support default methods:
> https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
> Here is the current error:
> {noformat}
> FTL stack trace ("~" means nesting-related):
>       - Failed at: #if task.switchable  [in template "...../home.ftl" at line 
> 43, column 25]
> ----
>       at 
> freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:131)
>       at 
> freemarker.core.UnexpectedTypeException.newDesciptionBuilder(UnexpectedTypeException.java:77)
>       at 
> freemarker.core.UnexpectedTypeException.<init>(UnexpectedTypeException.java:40)
>       at 
> freemarker.core.NonBooleanException.<init>(NonBooleanException.java:44)
>       at freemarker.core.Expression.modelToBoolean(Expression.java:142)
>       at freemarker.core.Expression.evalToBoolean(Expression.java:125)
>       at freemarker.core.Expression.evalToBoolean(Expression.java:110)
>       at freemarker.core.ConditionalBlock.accept(ConditionalBlock.java:46)
>       at freemarker.core.Environment.visit(Environment.java:324)
>       at freemarker.core.MixedContent.accept(MixedContent.java:54)
>       at 
> freemarker.core.Environment.visitByHiddingParent(Environment.java:345)
>       at 
> freemarker.core.IteratorBlock$IterationContext.executeNestedBlockInner(IteratorBlock.java:240)
>       at 
> freemarker.core.IteratorBlock$IterationContext.executeNestedBlock(IteratorBlock.java:220)
>       at 
> freemarker.core.IteratorBlock$IterationContext.accept(IteratorBlock.java:194)
>       at freemarker.core.Environment.visitIteratorBlock(Environment.java:572)
>       at freemarker.core.IteratorBlock.acceptWithResult(IteratorBlock.java:78)
>       at freemarker.core.IteratorBlock.accept(IteratorBlock.java:64)
>       at freemarker.core.Environment.visit(Environment.java:324)
>       at freemarker.core.MixedContent.accept(MixedContent.java:54)
>       at freemarker.core.Environment.visit(Environment.java:324)
>       at freemarker.core.Environment.process(Environment.java:302)
>       at freemarker.template.Template.process(Template.java:325)
>       at com.qwazr.tools.FreeMarkerTool.template(FreeMarkerTool.java:86)
>       at com.qwazr.tools.FreeMarkerTool.template(FreeMarkerTool.java:101)
> {noformat}
> To reproduce this.
> 1. Use an interface
> {code:java}
> public interface UpdatableTask extends Runnable {
>     default boolean isSwitchable() {
>         return false;
>     }
> }
> {code}
> 2. Use an object that implements this interface with the following template:
> {code}
> <#if task.switchable>
> ...
> </#if>
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Reply via email to