diff --git a/src/main/java/org/apache/ibatis/type/SqlxmlTypeHandler.java b/src/main/java/org/apache/ibatis/type/SqlxmlTypeHandler.java new file mode 100644 index 00000000000..0be63cdf572 --- /dev/null +++ b/src/main/java/org/apache/ibatis/type/SqlxmlTypeHandler.java @@ -0,0 +1,72 @@ +/** + * Copyright 2009-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ibatis.type; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLXML; + +/** + * Convert String to/from SQLXML. + * + * @since 3.5.0 + * @author Iwao AVE! + */ +public class SqlxmlTypeHandler extends BaseTypeHandler { + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) + throws SQLException { + SQLXML sqlxml = ps.getConnection().createSQLXML(); + try { + sqlxml.setString(parameter); + ps.setSQLXML(i, sqlxml); + } finally { + sqlxml.free(); + } + } + + @Override + public String getNullableResult(ResultSet rs, String columnName) throws SQLException { + return sqlxmlToString(rs.getSQLXML(columnName)); + } + + @Override + public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + return sqlxmlToString(rs.getSQLXML(columnIndex)); + } + + @Override + public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + return sqlxmlToString(cs.getSQLXML(columnIndex)); + } + + protected String sqlxmlToString(SQLXML sqlxml) throws SQLException { + if (sqlxml == null) { + return null; + } + try { + String result = sqlxml.getString(); + return result; + } finally { + sqlxml.free(); + } + } + +} diff --git a/src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java b/src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java index 3d3385aa222..a6f754ac7c7 100644 --- a/src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java +++ b/src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java @@ -145,6 +145,8 @@ public TypeHandlerRegistry() { register(java.sql.Time.class, new SqlTimeTypeHandler()); register(java.sql.Timestamp.class, new SqlTimestampTypeHandler()); + register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler()); + // mybatis-typehandlers-jsr310 if (Jdk.dateAndTimeApiExists) { this.register(Instant.class, InstantTypeHandler.class); diff --git a/src/test/java/org/apache/ibatis/type/SqlxmlTypeHandlerTest.java b/src/test/java/org/apache/ibatis/type/SqlxmlTypeHandlerTest.java new file mode 100644 index 00000000000..4219e74bbda --- /dev/null +++ b/src/test/java/org/apache/ibatis/type/SqlxmlTypeHandlerTest.java @@ -0,0 +1,167 @@ +/** + * Copyright 2009-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ibatis.type; + +import static org.junit.Assert.*; + +import java.io.Reader; +import java.nio.file.Paths; +import java.sql.Connection; +import java.util.Collections; + +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; +import org.apache.ibatis.io.Resources; +import org.apache.ibatis.jdbc.ScriptRunner; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.test.EmbeddedPostgresqlTests; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import ru.yandex.qatools.embed.postgresql.EmbeddedPostgres; +import ru.yandex.qatools.embed.postgresql.util.SocketUtil; + +@Category(EmbeddedPostgresqlTests.class) +public class SqlxmlTypeHandlerTest { + private static final EmbeddedPostgres postgres = new EmbeddedPostgres(); + + private static SqlSessionFactory sqlSessionFactory; + + @BeforeClass + public static void setUp() throws Exception { + // Launch PostgreSQL server. Download / unarchive if necessary. + String url = postgres.start( + EmbeddedPostgres.cachedRuntimeConfig(Paths.get(System.getProperty("java.io.tmpdir"), "pgembed")), "localhost", + SocketUtil.findFreePort(), "postgres_sqlxml", "postgres", "root", Collections.emptyList()); + + Configuration configuration = new Configuration(); + Environment environment = new Environment("development", new JdbcTransactionFactory(), new UnpooledDataSource( + "org.postgresql.Driver", url, null)); + configuration.setEnvironment(environment); + configuration.setUseGeneratedKeys(true); + configuration.addMapper(Mapper.class); + sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); + + try (SqlSession session = sqlSessionFactory.openSession(); + Connection conn = session.getConnection(); + Reader reader = Resources + .getResourceAsReader("org/apache/ibatis/type/SqlxmlTypeHandlerTest.sql")) { + ScriptRunner runner = new ScriptRunner(conn); + runner.setLogWriter(null); + runner.runScript(reader); + } + } + + @AfterClass + public static void tearDown() { + postgres.stop(); + } + + @Test + public void shouldReturnXmlAsString() throws Exception { + SqlSession session = sqlSessionFactory.openSession(); + try { + Mapper mapper = session.getMapper(Mapper.class); + XmlBean bean = mapper.select(1); + assertEquals("XML data", + bean.getContent()); + } finally { + session.close(); + } + } + + @Test + public void shouldReturnNull() throws Exception { + SqlSession session = sqlSessionFactory.openSession(); + try { + Mapper mapper = session.getMapper(Mapper.class); + XmlBean bean = mapper.select(2); + assertNull(bean.getContent()); + } finally { + session.close(); + } + } + + @Test + public void shouldInsertXmlString() throws Exception { + final Integer id = 100; + final String content = "Save XMLGet XML"; + // Insert + { + SqlSession session = sqlSessionFactory.openSession(); + try { + Mapper mapper = session.getMapper(Mapper.class); + XmlBean bean = new XmlBean(); + bean.setId(id); + bean.setContent(content); + mapper.insert(bean); + session.commit(); + } finally { + session.close(); + } + } + // Select to verify + { + SqlSession session = sqlSessionFactory.openSession(); + try { + Mapper mapper = session.getMapper(Mapper.class); + XmlBean bean = mapper.select(id); + assertEquals(content, bean.getContent()); + } finally { + session.close(); + } + } + } + + interface Mapper { + @Select("select id, content from mbtest.test_sqlxml where id = #{id}") + XmlBean select(Integer id); + + @Insert("insert into mbtest.test_sqlxml (id, content) values (#{id}, #{content,jdbcType=SQLXML})") + void insert(XmlBean bean); + } + + public static class XmlBean { + private Integer id; + + private String content; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + } +} diff --git a/src/test/java/org/apache/ibatis/type/SqlxmlTypeHandlerTest.sql b/src/test/java/org/apache/ibatis/type/SqlxmlTypeHandlerTest.sql new file mode 100644 index 00000000000..aae14168197 --- /dev/null +++ b/src/test/java/org/apache/ibatis/type/SqlxmlTypeHandlerTest.sql @@ -0,0 +1,28 @@ +-- +-- Copyright 2009-2018 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +CREATE SCHEMA mbtest; + +CREATE TABLE mbtest.test_sqlxml ( + id serial PRIMARY KEY, + content XML +); + +INSERT INTO mbtest.test_sqlxml (id, content) +VALUES (1, 'XML data'); + +INSERT INTO mbtest.test_sqlxml (id, content) +VALUES (2, NULL);