• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / displaytag / 1753

12 Feb 2026 03:17AM UTC coverage: 77.321% (-0.01%) from 77.334%
1753

push

github

web-flow
Merge pull request #1102 from hazendaz/renovate/javax-support-logback-monorepo

Update dependency ch.qos.logback:logback-classic to v1.5.29 (javax-support)

1438 of 2003 branches covered (71.79%)

Branch coverage included in aggregate %.

4034 of 5074 relevant lines covered (79.5%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.38
/displaytag/src/main/java/org/displaytag/decorator/Decorator.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2002-2026 Fabrizio Giustina, the Displaytag team
6
 */
7
package org.displaytag.decorator;
8

9
import java.beans.IndexedPropertyDescriptor;
10
import java.beans.PropertyDescriptor;
11
import java.lang.reflect.InvocationTargetException;
12
import java.util.Map;
13
import java.util.concurrent.ConcurrentHashMap;
14

15
import javax.servlet.jsp.PageContext;
16

17
import org.apache.commons.beanutils2.MappedPropertyDescriptor;
18
import org.apache.commons.beanutils2.PropertyUtils;
19
import org.displaytag.model.TableModel;
20

21
/**
22
 * This class provides some basic functionality for all objects which serve as decorators for the objects in the List
23
 * being displayed.
24
 * <p>
25
 * Decorator should never be subclassed directly. Use TableDecorator instead
26
 */
27
abstract class Decorator {
1✔
28

29
    /**
30
     * Char used to separate class name and property in the cache key.
31
     */
32
    private static final char CLASS_PROPERTY_SEPARATOR = '#';
33

34
    /**
35
     * property info cache contains classname#propertyname Strings as keys and Booleans as values.
36
     */
37
    private static Map<String, Boolean> propertyMap = new ConcurrentHashMap<>();
1✔
38

39
    /**
40
     * page context.
41
     */
42
    private PageContext pageContext;
43

44
    /**
45
     * decorated object. Usually a List
46
     */
47
    private Object decoratedObject;
48

49
    /**
50
     * The table model.
51
     *
52
     * @since 1.1
53
     */
54
    protected TableModel tableModel;
55

56
    /**
57
     * Initialize the TableTecorator instance.
58
     *
59
     * @param pageContext
60
     *            PageContext
61
     * @param decorated
62
     *            decorated object (usually a list)
63
     *
64
     * @see #init(PageContext, Object, TableModel)
65
     *
66
     * @deprecated use #init(PageContext, Object, TableModel)
67
     */
68
    @Deprecated
69
    public void init(final PageContext pageContext, final Object decorated) {
70
        this.init(pageContext, decorated, null);
×
71
    }
×
72

73
    /**
74
     * Initialize the TableTecorator instance.
75
     *
76
     * @param pageContext
77
     *            PageContext
78
     * @param decorated
79
     *            decorated object (usually a list)
80
     * @param tableModel
81
     *            table model
82
     */
83
    public void init(final PageContext pageContext, final Object decorated, final TableModel tableModel) {
84
        this.pageContext = pageContext;
1✔
85
        this.decoratedObject = decorated;
1✔
86
        this.tableModel = tableModel;
1✔
87
    }
1✔
88

89
    /**
90
     * returns the page context.
91
     *
92
     * @return PageContext
93
     */
94
    public PageContext getPageContext() {
95
        return this.pageContext;
1✔
96
    }
97

98
    /**
99
     * returns the decorated object.
100
     *
101
     * @return Object
102
     */
103
    public Object getDecoratedObject() {
104
        return this.decoratedObject;
1✔
105
    }
106

107
    /**
108
     * Called at the end of evaluation to clean up instance variable. A subclass of Decorator can override this method
109
     * but should always call super.finish() before return
110
     */
111
    public void finish() {
112
        this.pageContext = null;
1✔
113
        this.decoratedObject = null;
1✔
114
    }
1✔
115

116
    /**
117
     * Check if a getter exists for a given property. Uses cached info if property has already been requested. This
118
     * method only check for a simple property, if pPropertyName contains multiple tokens only the first part is
119
     * evaluated
120
     *
121
     * @param propertyName
122
     *            name of the property to check
123
     *
124
     * @return boolean true if the decorator has a getter for the given property
125
     */
126
    public boolean hasGetterFor(final String propertyName) {
127
        String simpleProperty = propertyName;
1✔
128

129
        // get the simple (not nested) bean property
130
        final int indexOfDot = simpleProperty.indexOf('.');
1✔
131
        if (indexOfDot > 0) {
1✔
132
            simpleProperty = simpleProperty.substring(0, indexOfDot);
1✔
133
        }
134

135
        final Boolean cachedResult = Decorator.propertyMap
1✔
136
                .get(this.getClass().getName() + Decorator.CLASS_PROPERTY_SEPARATOR + simpleProperty);
1✔
137

138
        if (cachedResult != null) {
1✔
139
            return cachedResult.booleanValue();
1✔
140
        }
141

142
        // not already cached... check
143
        final boolean hasGetter = this.searchGetterFor(propertyName);
1✔
144

145
        // save in cache
146
        Decorator.propertyMap.put(this.getClass().getName() + Decorator.CLASS_PROPERTY_SEPARATOR + simpleProperty,
1✔
147
                hasGetter);
1✔
148

149
        // and return
150
        return hasGetter;
1✔
151

152
    }
153

154
    /**
155
     * Looks for a getter for the given property using introspection.
156
     *
157
     * @param propertyName
158
     *            name of the property to check
159
     *
160
     * @return boolean true if the decorator has a getter for the given property
161
     */
162
    public boolean searchGetterFor(final String propertyName) {
163

164
        boolean result = false;
1✔
165

166
        try {
167
            // using getPropertyType instead of isReadable since isReadable doesn't support mapped properties.
168
            // Note that this method usually returns null if a property is not found and doesn't throw any exception
169
            // also for non existent properties
170
            final PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor(this, propertyName);
1✔
171

172
            if (pd != null) {
1✔
173
                // double check, see tests in TableDecoratorTest
174
                if (pd instanceof MappedPropertyDescriptor) {
1✔
175
                    result = ((MappedPropertyDescriptor) pd).getMappedReadMethod() != null;
1!
176
                } else if (pd instanceof IndexedPropertyDescriptor) {
1✔
177
                    result = ((IndexedPropertyDescriptor) pd).getIndexedReadMethod() != null;
1!
178
                } else {
179
                    result = pd.getReadMethod() != null;
1✔
180
                }
181
            }
182
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
×
183
            // ignore
184
        }
1✔
185

186
        return result;
1✔
187

188
    }
189

190
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc