DynamicContext.java

  1. /*
  2.  *    Copyright 2009-2024 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.apache.ibatis.scripting.xmltags;

  17. import java.util.HashMap;
  18. import java.util.Map;
  19. import java.util.StringJoiner;

  20. import ognl.OgnlContext;
  21. import ognl.OgnlRuntime;
  22. import ognl.PropertyAccessor;

  23. import org.apache.ibatis.reflection.MetaObject;
  24. import org.apache.ibatis.session.Configuration;

  25. /**
  26.  * @author Clinton Begin
  27.  */
  28. public class DynamicContext {

  29.   public static final String PARAMETER_OBJECT_KEY = "_parameter";
  30.   public static final String DATABASE_ID_KEY = "_databaseId";

  31.   static {
  32.     OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());
  33.   }

  34.   private final ContextMap bindings;
  35.   private final StringJoiner sqlBuilder = new StringJoiner(" ");
  36.   private int uniqueNumber;

  37.   public DynamicContext(Configuration configuration, Object parameterObject) {
  38.     if (parameterObject != null && !(parameterObject instanceof Map)) {
  39.       MetaObject metaObject = configuration.newMetaObject(parameterObject);
  40.       boolean existsTypeHandler = configuration.getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());
  41.       bindings = new ContextMap(metaObject, existsTypeHandler);
  42.     } else {
  43.       bindings = new ContextMap(null, false);
  44.     }
  45.     bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
  46.     bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
  47.   }

  48.   public Map<String, Object> getBindings() {
  49.     return bindings;
  50.   }

  51.   public void bind(String name, Object value) {
  52.     bindings.put(name, value);
  53.   }

  54.   public void appendSql(String sql) {
  55.     sqlBuilder.add(sql);
  56.   }

  57.   public String getSql() {
  58.     return sqlBuilder.toString().trim();
  59.   }

  60.   public int getUniqueNumber() {
  61.     return uniqueNumber++;
  62.   }

  63.   static class ContextMap extends HashMap<String, Object> {
  64.     private static final long serialVersionUID = 2977601501966151582L;
  65.     private final MetaObject parameterMetaObject;
  66.     private final boolean fallbackParameterObject;

  67.     public ContextMap(MetaObject parameterMetaObject, boolean fallbackParameterObject) {
  68.       this.parameterMetaObject = parameterMetaObject;
  69.       this.fallbackParameterObject = fallbackParameterObject;
  70.     }

  71.     @Override
  72.     public Object get(Object key) {
  73.       String strKey = (String) key;
  74.       if (super.containsKey(strKey)) {
  75.         return super.get(strKey);
  76.       }

  77.       if (parameterMetaObject == null) {
  78.         return null;
  79.       }

  80.       if (fallbackParameterObject && !parameterMetaObject.hasGetter(strKey)) {
  81.         return parameterMetaObject.getOriginalObject();
  82.       }
  83.       // issue #61 do not modify the context when reading
  84.       return parameterMetaObject.getValue(strKey);
  85.     }
  86.   }

  87.   static class ContextAccessor implements PropertyAccessor {

  88.     @Override
  89.     public Object getProperty(OgnlContext context, Object target, Object name) {
  90.       Map map = (Map) target;

  91.       Object result = map.get(name);
  92.       if (map.containsKey(name) || result != null) {
  93.         return result;
  94.       }

  95.       Object parameterObject = map.get(PARAMETER_OBJECT_KEY);
  96.       if (parameterObject instanceof Map) {
  97.         return ((Map) parameterObject).get(name);
  98.       }

  99.       return null;
  100.     }

  101.     @Override
  102.     public void setProperty(OgnlContext context, Object target, Object name, Object value) {
  103.       Map<Object, Object> map = (Map<Object, Object>) target;
  104.       map.put(name, value);
  105.     }

  106.     @Override
  107.     public String getSourceAccessor(OgnlContext arg0, Object arg1, Object arg2) {
  108.       return null;
  109.     }

  110.     @Override
  111.     public String getSourceSetter(OgnlContext arg0, Object arg1, Object arg2) {
  112.       return null;
  113.     }
  114.   }
  115. }