ArrayTypeHandler.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.type;

  17. import java.math.BigDecimal;
  18. import java.math.BigInteger;
  19. import java.net.URL;
  20. import java.sql.Array;
  21. import java.sql.CallableStatement;
  22. import java.sql.PreparedStatement;
  23. import java.sql.ResultSet;
  24. import java.sql.SQLException;
  25. import java.sql.Time;
  26. import java.sql.Timestamp;
  27. import java.time.LocalDate;
  28. import java.time.LocalDateTime;
  29. import java.time.LocalTime;
  30. import java.time.OffsetDateTime;
  31. import java.time.OffsetTime;
  32. import java.util.Calendar;
  33. import java.util.concurrent.ConcurrentHashMap;

  34. /**
  35.  * @author Clinton Begin
  36.  */
  37. public class ArrayTypeHandler extends BaseTypeHandler<Object> {

  38.   private static final ConcurrentHashMap<Class<?>, String> STANDARD_MAPPING;

  39.   static {
  40.     STANDARD_MAPPING = new ConcurrentHashMap<>();
  41.     STANDARD_MAPPING.put(BigDecimal.class, JdbcType.NUMERIC.name());
  42.     STANDARD_MAPPING.put(BigInteger.class, JdbcType.BIGINT.name());
  43.     STANDARD_MAPPING.put(boolean.class, JdbcType.BOOLEAN.name());
  44.     STANDARD_MAPPING.put(Boolean.class, JdbcType.BOOLEAN.name());
  45.     STANDARD_MAPPING.put(byte[].class, JdbcType.VARBINARY.name());
  46.     STANDARD_MAPPING.put(byte.class, JdbcType.TINYINT.name());
  47.     STANDARD_MAPPING.put(Byte.class, JdbcType.TINYINT.name());
  48.     STANDARD_MAPPING.put(Calendar.class, JdbcType.TIMESTAMP.name());
  49.     STANDARD_MAPPING.put(java.sql.Date.class, JdbcType.DATE.name());
  50.     STANDARD_MAPPING.put(java.util.Date.class, JdbcType.TIMESTAMP.name());
  51.     STANDARD_MAPPING.put(double.class, JdbcType.DOUBLE.name());
  52.     STANDARD_MAPPING.put(Double.class, JdbcType.DOUBLE.name());
  53.     STANDARD_MAPPING.put(float.class, JdbcType.REAL.name());
  54.     STANDARD_MAPPING.put(Float.class, JdbcType.REAL.name());
  55.     STANDARD_MAPPING.put(int.class, JdbcType.INTEGER.name());
  56.     STANDARD_MAPPING.put(Integer.class, JdbcType.INTEGER.name());
  57.     STANDARD_MAPPING.put(LocalDate.class, JdbcType.DATE.name());
  58.     STANDARD_MAPPING.put(LocalDateTime.class, JdbcType.TIMESTAMP.name());
  59.     STANDARD_MAPPING.put(LocalTime.class, JdbcType.TIME.name());
  60.     STANDARD_MAPPING.put(long.class, JdbcType.BIGINT.name());
  61.     STANDARD_MAPPING.put(Long.class, JdbcType.BIGINT.name());
  62.     STANDARD_MAPPING.put(OffsetDateTime.class, JdbcType.TIMESTAMP_WITH_TIMEZONE.name());
  63.     STANDARD_MAPPING.put(OffsetTime.class, JdbcType.TIME_WITH_TIMEZONE.name());
  64.     STANDARD_MAPPING.put(Short.class, JdbcType.SMALLINT.name());
  65.     STANDARD_MAPPING.put(String.class, JdbcType.VARCHAR.name());
  66.     STANDARD_MAPPING.put(Time.class, JdbcType.TIME.name());
  67.     STANDARD_MAPPING.put(Timestamp.class, JdbcType.TIMESTAMP.name());
  68.     STANDARD_MAPPING.put(URL.class, JdbcType.DATALINK.name());
  69.   }

  70.   public ArrayTypeHandler() {
  71.   }

  72.   @Override
  73.   public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
  74.       throws SQLException {
  75.     if (parameter instanceof Array) {
  76.       // it's the user's responsibility to properly free() the Array instance
  77.       ps.setArray(i, (Array) parameter);
  78.     } else {
  79.       if (!parameter.getClass().isArray()) {
  80.         throw new TypeException(
  81.             "ArrayType Handler requires SQL array or java array parameter and does not support type "
  82.                 + parameter.getClass());
  83.       }
  84.       Class<?> componentType = parameter.getClass().getComponentType();
  85.       String arrayTypeName = resolveTypeName(componentType);
  86.       Array array = ps.getConnection().createArrayOf(arrayTypeName, (Object[]) parameter);
  87.       ps.setArray(i, array);
  88.       array.free();
  89.     }
  90.   }

  91.   protected String resolveTypeName(Class<?> type) {
  92.     return STANDARD_MAPPING.getOrDefault(type, JdbcType.JAVA_OBJECT.name());
  93.   }

  94.   @Override
  95.   public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
  96.     return extractArray(rs.getArray(columnName));
  97.   }

  98.   @Override
  99.   public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
  100.     return extractArray(rs.getArray(columnIndex));
  101.   }

  102.   @Override
  103.   public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
  104.     return extractArray(cs.getArray(columnIndex));
  105.   }

  106.   protected Object extractArray(Array array) throws SQLException {
  107.     if (array == null) {
  108.       return null;
  109.     }
  110.     Object result = array.getArray();
  111.     array.free();
  112.     return result;
  113.   }

  114. }