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

mybatis / thymeleaf-scripting / #1164

pending completion
#1164

Pull #189

github

web-flow
Merge e930cb29c into 34bbfca66
Pull Request #189: Update dependency org.mybatis:mybatis-parent to v38

611 of 621 relevant lines covered (98.39%)

0.98 hits per line

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

95.45
/src/main/java/org/mybatis/scripting/thymeleaf/PropertyAccessor.java
1
/*
2
 *    Copyright 2018-2022 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
package org.mybatis.scripting.thymeleaf;
17

18
import java.beans.BeanInfo;
19
import java.beans.IntrospectionException;
20
import java.beans.Introspector;
21
import java.beans.PropertyDescriptor;
22
import java.lang.reflect.InvocationTargetException;
23
import java.util.Map;
24
import java.util.Optional;
25
import java.util.Set;
26
import java.util.concurrent.ConcurrentHashMap;
27
import java.util.stream.Collectors;
28
import java.util.stream.Stream;
29

30
/**
31
 * The interface for accessing a property. <br>
32
 * If you want to customize a default {@code PropertyAccessor}, you implements class of this interface and you need to
33
 * specify to a {@link SqlGenerator}. <br>
34
 *
35
 * @author Kazuki Shimizu
36
 *
37
 * @version 1.0.2
38
 */
39
public interface PropertyAccessor {
40

41
  /**
42
   * Get property names of specified type.
43
   *
44
   * @param type
45
   *          a target type
46
   *
47
   * @return property names
48
   */
49
  Set<String> getPropertyNames(Class<?> type);
50

51
  /**
52
   * Get a property type of specified property.
53
   *
54
   * @param type
55
   *          a target type
56
   * @param name
57
   *          a property name
58
   *
59
   * @return a property type
60
   */
61
  Class<?> getPropertyType(Class<?> type, String name);
62

63
  /**
64
   * Get a property value from specified target object.
65
   *
66
   * @param target
67
   *          a target object
68
   * @param name
69
   *          a property name
70
   *
71
   * @return a property value
72
   */
73
  Object getPropertyValue(Object target, String name);
74

75
  /**
76
   * Set a property value to the specified target object.
77
   *
78
   * @param target
79
   *          a target object
80
   * @param name
81
   *          a property name
82
   * @param value
83
   *          a property value
84
   */
85
  void setPropertyValue(Object target, String name, Object value);
86

87
  /**
88
   * The built-in property accessors.
89
   */
90
  enum BuiltIn implements PropertyAccessor {
1✔
91

92
    /**
93
     * The implementation using Java Beans API provided by JDK.
94
     */
95
    STANDARD(new StandardPropertyAccessor());
1✔
96

97
    private final PropertyAccessor delegate;
98

99
    BuiltIn(PropertyAccessor delegate) {
1✔
100
      this.delegate = delegate;
1✔
101
    }
1✔
102

103
    /**
104
     * {@inheritDoc}
105
     */
106
    @Override
107
    public Set<String> getPropertyNames(Class<?> type) {
108
      return delegate.getPropertyNames(type);
1✔
109
    }
110

111
    /**
112
     * {@inheritDoc}
113
     */
114
    @Override
115
    public Class<?> getPropertyType(Class<?> type, String name) {
116
      return delegate.getPropertyType(type, name);
1✔
117
    }
118

119
    /**
120
     * {@inheritDoc}
121
     */
122
    @Override
123
    public Object getPropertyValue(Object target, String name) {
124
      return delegate.getPropertyValue(target, name);
1✔
125
    }
126

127
    /**
128
     * {@inheritDoc}
129
     */
130
    @Override
131
    public void setPropertyValue(Object target, String name, Object value) {
132
      delegate.setPropertyValue(target, name, value);
1✔
133
    }
1✔
134

135
    static class StandardPropertyAccessor implements PropertyAccessor {
1✔
136

137
      private static Map<Class<?>, Map<String, PropertyDescriptor>> cache = new ConcurrentHashMap<>();
1✔
138

139
      /**
140
       * {@inheritDoc}
141
       */
142
      @Override
143
      public Set<String> getPropertyNames(Class<?> type) {
144
        return getPropertyDescriptors(type).keySet();
1✔
145
      }
146

147
      /**
148
       * {@inheritDoc}
149
       */
150
      @Override
151
      public Class<?> getPropertyType(Class<?> type, String name) {
152
        return Optional.ofNullable(getPropertyDescriptors(type).get(name))
1✔
153
            .orElseThrow(() -> new IllegalArgumentException(String.format(
1✔
154
                "Does not get a property type because property '%s' not found on '%s' class.", name, type.getName())))
1✔
155
            .getPropertyType();
1✔
156
      }
157

158
      /**
159
       * {@inheritDoc}
160
       */
161
      @Override
162
      public Object getPropertyValue(Object target, String name) {
163
        try {
164
          return Optional.ofNullable(getPropertyDescriptors(target.getClass()).get(name))
1✔
165
              .map(PropertyDescriptor::getReadMethod)
1✔
166
              .orElseThrow(() -> new IllegalArgumentException(
1✔
167
                  String.format("Does not get a property value because property '%s' not found on '%s' class.", name,
1✔
168
                      target.getClass().getName())))
1✔
169
              .invoke(target);
1✔
170
        } catch (IllegalAccessException | InvocationTargetException e) {
1✔
171
          throw new IllegalStateException(e);
1✔
172
        }
173
      }
174

175
      /**
176
       * {@inheritDoc}
177
       */
178
      @Override
179
      public void setPropertyValue(Object target, String name, Object value) {
180
        try {
181
          Optional.ofNullable(getPropertyDescriptors(target.getClass()).get(name))
1✔
182
              .map(PropertyDescriptor::getWriteMethod)
1✔
183
              .orElseThrow(() -> new IllegalArgumentException(
1✔
184
                  String.format("Does not set a property value because property '%s' not found on '%s' class.", name,
1✔
185
                      target.getClass().getName())))
1✔
186
              .invoke(target, value);
1✔
187
        } catch (IllegalAccessException | InvocationTargetException e) {
1✔
188
          throw new IllegalStateException(e);
1✔
189
        }
1✔
190
      }
1✔
191

192
      /**
193
       * Clear cache.
194
       * <p>
195
       * This method use by internal processing.
196
       * </p>
197
       */
198
      static void clearCache() {
199
        cache.clear();
1✔
200
      }
1✔
201

202
      private static Map<String, PropertyDescriptor> getPropertyDescriptors(Class<?> type) {
203
        return cache.computeIfAbsent(type, key -> {
1✔
204
          try {
205
            BeanInfo beanInfo = Introspector.getBeanInfo(type);
1✔
206
            return Stream.of(beanInfo.getPropertyDescriptors()).filter(x -> !x.getName().equals("class"))
1✔
207
                .collect(Collectors.toMap(PropertyDescriptor::getName, v -> v));
1✔
208
          } catch (IntrospectionException e) {
×
209
            throw new IllegalStateException(e);
×
210
          } finally {
211
            Introspector.flushFromCaches(type);
1✔
212
          }
213
        });
214
      }
215

216
    }
217

218
  }
219

220
}
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

© 2025 Coveralls, Inc