Hi,

Thanks, this really helps.

Just curious; What is the reason for making this distinction?
Why does the DefaultObjectWrapper expose the getters of a Pojo, but it does
not expose them if it implements one of the mentioned collections?
Is it possible to combine the two effects and do both (both making it #list
capable and getting the custom fields)?

Niels

On Mon, Mar 24, 2025 at 9:28 PM Daniel Dekany <daniel.dek...@gmail.com>
wrote:

> It's because if Team implements Set, List, Map, etc., then, by default, it
> will only see the Collection/Map elements, and not the Java methods of the
> object.
>
> Probably the cleanest/idiomatic solution is if Team is not a Set, but
> instead has a method like Set<User> getUsers(). Regardless of FreeMarker,
> that's what I would do as a Java programmer.
>
> But if it must be a Set, you can force FreeMarker to ignore that like this:
>
> So you can do this:
>
>     public static class CustomObjectWrapper extends DefaultObjectWrapper {
>         public CustomObjectWrapper(Version incompatibleImprovements) {
>             super(incompatibleImprovements);
>         }
>
>         @Override
>         public TemplateModel wrap(Object obj) throws TemplateModelException
> {
>             if (obj instanceof Team) {
>                 return new GenericObjectModel(obj, this);
>             }
>             return super.wrap(obj);
>         }
>     }
>
> and then where you create your Configuration singleton:
>
>   configuration.setObjectWrapper(new
> CustomObjectWrapper(Configuration.VERSION_2_3_35));
>
> Although now that being a Set was ignored, team is not #list-able in the
> template (except with directly calling the Set API-s).
>
>
> On Mon, Mar 24, 2025 at 12:00 PM Niels Basjes <ni...@basjes.nl> wrote:
>
> > Hi,
> >
> > I'm new to Freemarker and I'm looking for the right solution for
> > something I ran into but have not been able to figure out.
> >
> > If I have a Java class like this:
> >
> > public static class Team {
> >     private final String name;
> >     public Team(String name) {
> >         this.name = name;
> >     }
> >     public String getName() {
> >         return name;
> >     }
> > }
> >
> > If I then make a TemplateTest like this
> >
> > @Test
> > public void testTeamName() throws Exception {
> >     Team team = new Team("Working");
> >     addToDataModel("team", team);
> >     assertEquals("Working", team.getName());
> >     assertOutput("${team.name}","Working");
> > }
> >
> > and it all works.
> > If I change my Team to be a subclass of a well known collection (I have
> > tried TreeMap, TreeSet and ArrayList) then my .name attribute is no
> longer
> > available in a template.
> >
> > public static class TeamSet extends TreeSet<User> {
> >
> >
> > What is the proper way to solve this?
> > Perhaps a custom Object Wrapper?
> > Or is this something I should report as a bug?
> >
> > Thanks.
> >
> > Niels Basjes
> > nielsbas...@apache.org
> > ni...@basjes.nl
> >
>
>
> --
> Best regards,
> Daniel Dekany
>

Reply via email to