• 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

100.0
/src/main/java/org/mybatis/scripting/thymeleaf/processor/MyBatisParamTagProcessor.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.processor;
17

18
import java.lang.reflect.Array;
19
import java.util.Collection;
20
import java.util.function.UnaryOperator;
21

22
import org.mybatis.scripting.thymeleaf.MyBatisBindingContext;
23
import org.thymeleaf.context.ITemplateContext;
24
import org.thymeleaf.engine.AttributeName;
25
import org.thymeleaf.engine.EngineEventUtils;
26
import org.thymeleaf.engine.IterationStatusVar;
27
import org.thymeleaf.model.IProcessableElementTag;
28
import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
29
import org.thymeleaf.processor.element.IElementTagStructureHandler;
30
import org.thymeleaf.standard.expression.IStandardExpression;
31
import org.thymeleaf.standard.expression.StandardExpressionExecutionContext;
32
import org.thymeleaf.templatemode.TemplateMode;
33

34
/**
35
 * The processor class for handling the {@code mb:p} tag. <br>
36
 * This processor render bind variable(default: {@code #{…​}}) expression that can parsed data access library and
37
 * register an iteration object to the bind variables.
38
 *
39
 * @author Kazuki Shimizu
40
 *
41
 * @version 1.0.0
42
 */
43
public class MyBatisParamTagProcessor extends AbstractAttributeTagProcessor {
44

45
  private static final int PRECEDENCE = 1400;
46
  private static final String ATTR_NAME = "p";
47

48
  private final StandardExpressionExecutionContext expressionExecutionContext;
49

50
  private UnaryOperator<String> bindVariableRender = BindVariableRender.BuiltIn.MYBATIS;
1✔
51

52
  /**
53
   * Constructor that can be specified the template mode and dialect prefix.
54
   *
55
   * @param templateMode
56
   *          A target template mode
57
   * @param prefix
58
   *          A target dialect prefix
59
   */
60
  public MyBatisParamTagProcessor(final TemplateMode templateMode, final String prefix) {
61
    super(templateMode, prefix, null, false, ATTR_NAME, true, PRECEDENCE, true);
1✔
62
    expressionExecutionContext = templateMode == TemplateMode.TEXT ? StandardExpressionExecutionContext.RESTRICTED
1✔
63
        : StandardExpressionExecutionContext.NORMAL;
1✔
64
  }
1✔
65

66
  /**
67
   * Set a custom bind variable render function.<br>
68
   * By default, render {@literal #{...}} format.
69
   *
70
   * @param bindVariableRender
71
   *          a custom bind variable render function
72
   *
73
   * @since 1.0.2
74
   */
75
  public void setBindVariableRender(UnaryOperator<String> bindVariableRender) {
76
    this.bindVariableRender = bindVariableRender;
1✔
77
  }
1✔
78

79
  /**
80
   * {@inheritDoc}
81
   */
82
  @Override
83
  protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
84
      String attributeValue, IElementTagStructureHandler structureHandler) {
85
    if (attributeValue.contains("${")) {
1✔
86
      attributeValue = getExpressionEvaluatedText(context, tag, attributeName, attributeValue);
1✔
87
    }
88

89
    Pair parameterAndOptionPair = Pair.parse(attributeValue, ',');
1✔
90
    String parameterPath = parameterAndOptionPair.left;
1✔
91
    String options = parameterAndOptionPair.right;
1✔
92

93
    Pair objectNameAndPropertyPathPair = Pair.parse(parameterPath, '.');
1✔
94
    String objectName = objectNameAndPropertyPathPair.left;
1✔
95
    String nestedPropertyPath = objectNameAndPropertyPathPair.right;
1✔
96

97
    String body;
98
    String iterationObjectName = objectName + "Stat";
1✔
99
    if (context.containsVariable(iterationObjectName)) {
1✔
100
      MyBatisBindingContext bindingContext = MyBatisBindingContext.load(context);
1✔
101
      IterationStatusVar iterationStatus = (IterationStatusVar) context.getVariable(iterationObjectName);
1✔
102
      String iterationObjectVariableName = bindingContext.generateUniqueName(objectName, iterationStatus);
1✔
103
      if (!bindingContext.containsCustomBindVariable(iterationObjectVariableName)) {
1✔
104
        bindingContext.setCustomBindVariable(iterationObjectVariableName, iterationStatus.getCurrent());
1✔
105
      }
106
      if (nestedPropertyPath.isEmpty()) {
1✔
107
        body = bindVariableRender.apply(iterationObjectVariableName + options);
1✔
108
      } else {
109
        Object value = getExpressionEvaluatedValue(context, tag, attributeName, parameterPath);
1✔
110
        if (isCollectionOrArray(value)) {
1✔
111
          body = generateCollectionBindVariables(value, iterationObjectVariableName + nestedPropertyPath, options);
1✔
112
        } else {
113
          body = bindVariableRender.apply(iterationObjectVariableName + nestedPropertyPath + options);
1✔
114
        }
115
      }
116
    } else {
1✔
117
      Object value = nestedPropertyPath.isEmpty() ? context.getVariable(objectName)
1✔
118
          : getExpressionEvaluatedValue(context, tag, attributeName, parameterPath);
1✔
119
      if (isCollectionOrArray(value)) {
1✔
120
        body = generateCollectionBindVariables(value, parameterPath, options);
1✔
121
      } else {
122
        body = bindVariableRender.apply(attributeValue);
1✔
123
      }
124
    }
125
    structureHandler.setBody(body, false);
1✔
126
  }
1✔
127

128
  private Object getExpressionEvaluatedValue(ITemplateContext context, IProcessableElementTag tag,
129
      AttributeName attributeName, String parameterValue) {
130
    IStandardExpression expression = EngineEventUtils.computeAttributeExpression(context, tag, attributeName,
1✔
131
        "${" + parameterValue + "}");
132
    return expression.execute(context, this.expressionExecutionContext);
1✔
133
  }
134

135
  private String getExpressionEvaluatedText(ITemplateContext context, IProcessableElementTag tag,
136
      AttributeName attributeName, String parameterValue) {
137
    IStandardExpression expression = EngineEventUtils.computeAttributeExpression(context, tag, attributeName,
1✔
138
        "|" + parameterValue + "|");
139
    return expression.execute(context, this.expressionExecutionContext).toString();
1✔
140
  }
141

142
  private boolean isCollectionOrArray(Object value) {
143
    return value != null && (Collection.class.isAssignableFrom(value.getClass()) || value.getClass().isArray());
1✔
144
  }
145

146
  private String generateCollectionBindVariables(Object value, String parameterPath, String options) {
147
    int size = value.getClass().isArray() ? Array.getLength(value) : ((Collection) value).size();
1✔
148
    if (size == 0) {
1✔
149
      return "null";
1✔
150
    } else {
151
      StringBuilder sb = new StringBuilder();
1✔
152
      for (int i = 0; i < size; i++) {
1✔
153
        if (i != 0) {
1✔
154
          sb.append(", ");
1✔
155
        }
156
        sb.append(bindVariableRender.apply(parameterPath + "[" + i + "]" + options));
1✔
157
      }
158
      return sb.toString();
1✔
159
    }
160
  }
161

162
  private static class Pair {
163

164
    private final String left;
165
    private final String right;
166

167
    private Pair(String left, String right) {
1✔
168
      this.left = left;
1✔
169
      this.right = right;
1✔
170
    }
1✔
171

172
    private static Pair parse(String value, char separator) {
173
      int separatorIndex = value.indexOf(separator);
1✔
174
      String left;
175
      String right;
176
      if (separatorIndex == -1) {
1✔
177
        left = value;
1✔
178
        right = "";
1✔
179
      } else {
180
        left = value.substring(0, separatorIndex);
1✔
181
        right = value.substring(separatorIndex);
1✔
182
      }
183
      return new Pair(left, right);
1✔
184
    }
185

186
  }
187

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