View Javadoc

1   /*
2    * $Id: StrutsBeanWrapper.java 474191 2006-11-13 08:30:40Z mrdon $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts2.views.freemarker;
22  
23  import java.util.Map;
24  import java.util.Set;
25  
26  import org.apache.struts2.StrutsConstants;
27  
28  import freemarker.core.CollectionAndSequence;
29  import freemarker.ext.beans.BeansWrapper;
30  import freemarker.ext.beans.MapModel;
31  import freemarker.ext.util.ModelFactory;
32  import freemarker.template.ObjectWrapper;
33  import freemarker.template.SimpleSequence;
34  import freemarker.template.TemplateBooleanModel;
35  import freemarker.template.TemplateCollectionModel;
36  import freemarker.template.TemplateHashModelEx;
37  import freemarker.template.TemplateModel;
38  import freemarker.template.TemplateModelException;
39  
40  /***
41   * <!-- START SNIPPET: javadoc -->
42   *
43   * The StrutsBeanWrapper extends the default FreeMarker BeansWrapper and provides almost no change in functionality,
44   * <b>except</b> for how it handles maps. Normally, FreeMarker has two modes of operation: either support for friendly
45   * map built-ins (?keys, ?values, etc) but only support for String keys; OR no special built-in support (ie: ?keys
46   * returns the methods on the map instead of the keys) but support for String and non-String keys alike. Struts
47   * provides an alternative implementation that gives us the best of both worlds.
48   *
49   * <p/> It is possible that this special behavior may be confusing or can cause problems. Therefore, you can set the
50   * <b>struts.freemarker.wrapper.altMap</b> property in struts.properties to false, allowing the normal BeansWrapper
51   * logic to take place instead.
52   *
53   * <!-- END SNIPPET: javadoc -->
54   */
55  public class StrutsBeanWrapper extends BeansWrapper {
56      private boolean altMapWrapper;
57      
58      StrutsBeanWrapper(boolean altMapWrapper) {
59          this.altMapWrapper = altMapWrapper;
60      }
61  
62      public TemplateModel wrap(Object object) throws TemplateModelException {
63          if (object instanceof TemplateBooleanModel) {
64              return super.wrap(object);
65          }
66  
67          // attempt to get the best of both the SimpleMapModel and the MapModel of FM.
68          if (altMapWrapper && object instanceof Map) {
69              return getInstance(object, FriendlyMapModel.FACTORY);
70          }
71  
72          return super.wrap(object);
73      }
74  
75      /***
76       * Attempting to get the best of both worlds of FM's MapModel and SimpleMapModel, by reimplementing the isEmpty(),
77       * keySet() and values() methods. ?keys and ?values built-ins are thus available, just as well as plain Map
78       * methods.
79       */
80      private final static class FriendlyMapModel extends MapModel implements TemplateHashModelEx {
81          static final ModelFactory FACTORY = new ModelFactory() {
82              public TemplateModel create(Object object, ObjectWrapper wrapper) {
83                  return new FriendlyMapModel((Map) object, (BeansWrapper) wrapper);
84              }
85          };
86  
87          public FriendlyMapModel(Map map, BeansWrapper wrapper) {
88              super(map, wrapper);
89          }
90  
91          public boolean isEmpty() {
92              return ((Map) object).isEmpty();
93          }
94  
95          protected Set keySet() {
96              return ((Map) object).keySet();
97          }
98  
99          public TemplateCollectionModel values() {
100             return new CollectionAndSequence(new SimpleSequence(((Map) object).values(), wrapper));
101         }
102     }
103 }