Very similar to {@link org.springframework.jdbc.support.SQLExceptionTranslator}.
9 | */ 10 | @FunctionalInterface 11 | public interface SQLExceptionAdapter { 12 | 13 | /** 14 | * Translates a checked {@link SQLException} to an unchecked exception. 15 | * Does not throw the exception, only creates an instance 16 | * 17 | * @param procedureName the SQL procedure name derived by this library 18 | * @param sql the JDBC call string generated by this library 19 | * @param exception the exception to translate, should be passed as cause to 20 | * the new exception instance returned by this method 21 | * @return the unchecked exception instance 22 | */ 23 | RuntimeException translate(String procedureName, String sql, SQLException exception); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/marschall/storedprocedureproxy/UncheckedSQLException.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy; 2 | 3 | import java.sql.SQLException; 4 | import java.util.Objects; 5 | 6 | /** 7 | * Wraps an {@link SQLException} with an unchecked exception. 8 | * 9 | * @see java.io.UncheckedIOException 10 | */ 11 | public final class UncheckedSQLException extends RuntimeException { 12 | 13 | private static final long serialVersionUID = 1L; 14 | 15 | UncheckedSQLException(SQLException cause) { 16 | super(Objects.requireNonNull(cause)); 17 | } 18 | 19 | UncheckedSQLException(String message, SQLException cause) { 20 | super(message, Objects.requireNonNull(cause)); 21 | } 22 | 23 | /** 24 | * Convenience method that returns the cause as type {@link SQLException} 25 | * avoiding the need to cast the result. 26 | * 27 | * @return the exception cause, never {@code null} 28 | */ 29 | @Override 30 | public SQLException getCause() { 31 | return (SQLException) super.getCause(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/marschall/storedprocedureproxy/annotations/ParameterType.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.annotations; 2 | 3 | import static java.lang.annotation.ElementType.PARAMETER; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import com.github.marschall.storedprocedureproxy.spi.TypeMapper; 11 | 12 | /** 13 | * Defines the SQL type of an in parameter. 14 | * 15 | * @see Binding Parameters 16 | */ 17 | @Documented 18 | @Retention(RUNTIME) 19 | @Target(PARAMETER) 20 | public @interface ParameterType { 21 | 22 | /** 23 | * Defines the SQL type of an in parameter. If nothing is specified the default 24 | * from {@link TypeMapper} is used. 25 | * 26 | * @return the parameter SQL type, can be a vendor type 27 | * @see java.sql.Types 28 | */ 29 | int value(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/ToStringUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import java.lang.annotation.Annotation; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import com.github.marschall.storedprocedureproxy.ProcedureCallerFactory.ProcedureCaller; 10 | 11 | public class ToStringUtilsTest { 12 | 13 | @Test 14 | public void fetchSizeToString() { 15 | assertEquals("default", ToStringUtils.fetchSizeToString(ProcedureCaller.DEFAULT_FETCH_SIZE)); 16 | assertEquals("1", ToStringUtils.fetchSizeToString(1)); 17 | } 18 | 19 | @Test 20 | public void classNameToString() { 21 | assertEquals("String", ToStringUtils.classNameToString(java.lang.String.class)); 22 | assertEquals("java.lang.annotation.Annotation", ToStringUtils.classNameToString(Annotation.class)); 23 | assertEquals("com.github.marschall.storedprocedureproxy.ToStringUtilsTest", ToStringUtils.classNameToString(ToStringUtilsTest.class)); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/marschall/storedprocedureproxy/annotations/Schema.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.annotations; 2 | 3 | import static java.lang.annotation.ElementType.TYPE; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Defines the name of a database schema. 12 | * 13 | *If the schema name is not static you can use something like this:
14 | *ProcedureCallerFactory.of(MyProcedures.class, dataSource)
15 | * .withSchemaNamingStrategy(ignored -> computeSchemaName())
16 | * .build();
17 | *
18 | * For PL/SQL packages or DB2 modules {@link Namespace} should be 19 | * used.
20 | */ 21 | @Documented 22 | @Retention(RUNTIME) 23 | @Target(TYPE) 24 | public @interface Schema { 25 | 26 | 27 | /** 28 | * Defines the name of the database schema. 29 | * 30 | * @return the name of the database schema 31 | */ 32 | String value() default ""; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/marschall/storedprocedureproxy/annotations/ParameterName.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.annotations; 2 | 3 | import static java.lang.annotation.ElementType.PARAMETER; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import com.github.marschall.storedprocedureproxy.ProcedureCallerFactory.ParameterRegistration; 11 | 12 | /** 13 | * Defines the name of an in parameter. Only used if the parameter registration 14 | * is either {@link ParameterRegistration#NAME_ONLY} or 15 | * {@link ParameterRegistration#NAME_AND_TYPE}. 16 | * 17 | * @see Binding Parameters 18 | */ 19 | @Documented 20 | @Retention(RUNTIME) 21 | @Target(PARAMETER) 22 | public @interface ParameterName { 23 | 24 | /** 25 | * Defines the name of the in parameter. 26 | * 27 | * @return the name of the in parameter 28 | */ 29 | String value(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/github/marschall/storedprocedureproxy/OracleTypeMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy; 2 | 3 | import com.github.marschall.storedprocedureproxy.spi.TypeMapper; 4 | 5 | /** 6 | * Like {@link DefaultTypeMapper} but maps {@code boolean} to 7 | * 252. 8 | * 9 | * @see OracleTypes.PLSQL_BOOLEAN 10 | */ 11 | final class OracleTypeMapper implements TypeMapper { 12 | 13 | static final TypeMapper INSTANCE = new OracleTypeMapper(); 14 | 15 | private static final int PLSQL_BOOLEAN = 252; 16 | 17 | private OracleTypeMapper() { 18 | // private constructor, avoid instantiation 19 | super(); 20 | } 21 | 22 | @Override 23 | public int mapToSqlType(Class> javaType) { 24 | if (javaType == Boolean.class || javaType == boolean.class) { 25 | return PLSQL_BOOLEAN; 26 | } 27 | return DefaultTypeMapper.INSTANCE.mapToSqlType(javaType); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/marschall/storedprocedureproxy/ValueExtractor.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | /** 7 | * Extracts a value from a single row. 8 | * 9 | *This class is used to extract a value object from every row in a 10 | * ref cursor out parameter.
11 | * 12 | *Implementations should not catch {@link SQLException} this will 13 | * be done by a higher layer.
14 | * 15 | * @paramImplementations should not call {@link ResultSet#next()} but 25 | * instead expect to be called for every method. 26 | * 27 | * @param resultSet the ResultSet to the value of the current row from 28 | * @return the value for the current row 29 | * @throws SQLException propagated if a method on {@link ResultSet} throws an exception 30 | */ 31 | V extractValue(ResultSet resultSet) throws SQLException; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/marschall/storedprocedureproxy/annotations/Namespace.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.annotations; 2 | 3 | import static java.lang.annotation.ElementType.TYPE; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Defines the namespace of a stored procedure. 12 | * 13 | *
This should be used for Oracle 14 | * PL/SQL Packages 15 | * or IBM DB2 Modules.
16 | * 17 | * @see Oracle Packages 18 | */ 19 | @Documented 20 | @Retention(RUNTIME) 21 | @Target(TYPE) 22 | public @interface Namespace { 23 | 24 | 25 | /** 26 | * Defines the namespace of a stored procedure. 27 | * 28 | * @return the namespace of a stored procedure 29 | */ 30 | String value() default ""; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/configuration/MariaDBConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.configuration; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import org.springframework.beans.factory.BeanCreationException; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.jdbc.datasource.SingleConnectionDataSource; 9 | 10 | @Configuration 11 | public class MariaDBConfiguration { 12 | 13 | @Bean 14 | public DataSource dataSource() { 15 | try { 16 | Class.forName("org.mariadb.jdbc.Driver"); 17 | } catch (ClassNotFoundException e) { 18 | throw new BeanCreationException("mariadb driver not present", e); 19 | } 20 | SingleConnectionDataSource dataSource = new SingleConnectionDataSource(); 21 | dataSource.setSuppressClose(true); 22 | // https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/ 23 | dataSource.setUrl("jdbc:mariadb://localhost:3307/jdbc"); 24 | dataSource.setUsername("jdbc"); 25 | dataSource.setPassword("Cent-Quick-Space-Bath-8"); 26 | return dataSource; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/resources/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Philippe Marschall (philippe.marschall@gmail.com) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/configuration/OracleConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.configuration; 2 | 3 | import java.util.Properties; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.jdbc.datasource.SingleConnectionDataSource; 10 | 11 | import oracle.jdbc.OracleConnection; 12 | 13 | @Configuration 14 | public class OracleConfiguration { 15 | 16 | @Bean 17 | public DataSource dataSource() { 18 | oracle.jdbc.OracleDriver.isDebug(); 19 | SingleConnectionDataSource dataSource = new SingleConnectionDataSource(); 20 | dataSource.setSuppressClose(true); 21 | dataSource.setUrl("jdbc:oracle:thin:@localhost:1521/FREEPDB1"); 22 | dataSource.setUsername("jdbc"); 23 | dataSource.setPassword("Cent-Quick-Space-Bath-8"); 24 | Properties connectionProperties = new Properties(); 25 | connectionProperties.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_DISABLE_OUT_OF_BAND_BREAK, "true"); 26 | dataSource.setConnectionProperties(connectionProperties); 27 | return dataSource; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/configuration/MssqlConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.configuration; 2 | 3 | import java.sql.SQLException; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.springframework.beans.factory.BeanCreationException; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.jdbc.datasource.SingleConnectionDataSource; 11 | 12 | @Configuration 13 | public class MssqlConfiguration { 14 | 15 | @Bean 16 | public DataSource dataSource() { 17 | try { 18 | if (!com.microsoft.sqlserver.jdbc.SQLServerDriver.isRegistered()) { 19 | com.microsoft.sqlserver.jdbc.SQLServerDriver.register(); 20 | } 21 | } catch (SQLException e) { 22 | throw new BeanCreationException("could not register driver", e); 23 | } 24 | SingleConnectionDataSource dataSource = new SingleConnectionDataSource(); 25 | dataSource.setSuppressClose(true); 26 | dataSource.setUrl("jdbc:sqlserver://localhost:1433;databaseName=master;encrypt=false"); 27 | dataSource.setUsername("sa"); 28 | dataSource.setPassword("Cent-Quick-Space-Bath-8"); 29 | return dataSource; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/SpringSQLExceptionAdapterTest.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertNotNull; 4 | import static org.mockito.ArgumentMatchers.any; 5 | import static org.mockito.ArgumentMatchers.anyString; 6 | import static org.mockito.Mockito.mock; 7 | import static org.mockito.Mockito.when; 8 | 9 | import java.sql.SQLException; 10 | 11 | import org.junit.jupiter.api.Test; 12 | import org.springframework.dao.DataAccessException; 13 | import org.springframework.jdbc.support.SQLExceptionTranslator; 14 | 15 | class SpringSQLExceptionAdapterTest { 16 | 17 | /** 18 | * Regression test for #71 19 | */ 20 | @Test 21 | void translateReturnsNull() { 22 | SQLExceptionTranslator translator = mock(SQLExceptionTranslator.class); 23 | when(translator.translate(anyString(), anyString(), any(SQLException.class))).thenReturn(null); 24 | 25 | SpringSQLExceptionAdapter adapter = new SpringSQLExceptionAdapter(translator); 26 | 27 | DataAccessException translated = adapter.translate("simple_function", "{call simple_function()}", new SQLException()); 28 | assertNotNull(translated); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java16/com/github/marschall/storedprocedureproxy/Java16DefaultMethodSupport.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | 8 | final class Java16DefaultMethodSupport implements DefaultMethodSupport { 9 | 10 | static final DefaultMethodSupport INSTANCE = new Java16DefaultMethodSupport(); 11 | 12 | private static final MethodHandle INVOKE_DEFAULT; 13 | 14 | static { 15 | MethodHandle invokeDefaultHandle; 16 | try { 17 | Method invokeDefaultMethod = InvocationHandler.class 18 | .getDeclaredMethod("invokeDefault", Object.class, Method.class, Object[].class); 19 | invokeDefaultHandle = MethodHandles.lookup().unreflect(invokeDefaultMethod); 20 | } catch (ReflectiveOperationException e) { 21 | throw new RuntimeException("could not initialize class", e); 22 | } 23 | INVOKE_DEFAULT = invokeDefaultHandle; 24 | } 25 | 26 | private Java16DefaultMethodSupport() { 27 | super(); 28 | } 29 | 30 | @Override 31 | public Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable { 32 | return INVOKE_DEFAULT.invokeExact(proxy, method, args); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/configuration/FirebirdConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.configuration; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import org.springframework.beans.factory.BeanCreationException; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.jdbc.datasource.SingleConnectionDataSource; 9 | 10 | @Configuration 11 | public class FirebirdConfiguration { 12 | 13 | 14 | @Bean 15 | public DataSource dataSource() { 16 | try { 17 | Class.forName("org.firebirdsql.jdbc.FBDriver"); 18 | } catch (ClassNotFoundException e) { 19 | throw new BeanCreationException("firebird driver not present", e); 20 | } 21 | SingleConnectionDataSource dataSource = new SingleConnectionDataSource(); 22 | dataSource.setSuppressClose(true); 23 | // https://www.firebirdsql.org/file/documentation/drivers_documentation/java/faq.html#jdbc-urls-java.sql.drivermanager 24 | // https://github.com/FirebirdSQL/jaybird/wiki/Jaybird-and-Firebird-3 25 | dataSource.setUrl("jdbc:firebirdsql://localhost:3050/jdbc?charSet=utf-8"); 26 | // https://github.com/almeida/docker-firebird 27 | dataSource.setUsername("jdbc"); 28 | dataSource.setPassword("Cent-Quick-Space-Bath-8"); 29 | return dataSource; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/configuration/PostgresConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy.configuration; 2 | 3 | import static com.github.marschall.storedprocedureproxy.Travis.isTravis; 4 | 5 | import java.sql.SQLException; 6 | 7 | import javax.sql.DataSource; 8 | 9 | import org.springframework.beans.factory.BeanCreationException; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.jdbc.datasource.SingleConnectionDataSource; 13 | 14 | @Configuration 15 | public class PostgresConfiguration { 16 | 17 | @Bean 18 | public DataSource dataSource() { 19 | try { 20 | if (!org.postgresql.Driver.isRegistered()) { 21 | org.postgresql.Driver.register(); 22 | } 23 | } catch (SQLException e) { 24 | throw new BeanCreationException("could not register driver", e); 25 | } 26 | SingleConnectionDataSource dataSource = new SingleConnectionDataSource(); 27 | dataSource.setSuppressClose(true); 28 | String userName = System.getProperty("user.name"); 29 | // defaults from Postgres.app 30 | dataSource.setUrl("jdbc:postgresql:" + userName); 31 | dataSource.setUsername(userName); 32 | String password = isTravis() ? "" : "Cent-Quick-Space-Bath-8"; 33 | dataSource.setPassword(password); 34 | return dataSource; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/github/marschall/storedprocedureproxy/Usage.java: -------------------------------------------------------------------------------- 1 | package com.github.marschall.storedprocedureproxy; 2 | 3 | import javax.naming.InitialContext; 4 | import javax.naming.NamingException; 5 | import javax.sql.DataSource; 6 | 7 | import com.github.marschall.storedprocedureproxy.ProcedureCallerFactory.ParameterRegistration; 8 | import com.github.marschall.storedprocedureproxy.procedures.PostgresProcedures; 9 | 10 | public class Usage { 11 | 12 | public static void simpleUsage() throws NamingException { 13 | DataSource dataSource = (DataSource) new InitialContext().lookup("java:comp/DefaultDataSource"); 14 | ClassThis is only really useful for methods that use cursors or 16 | * {@link ResultSet}s to return multiple rows.
17 | * 18 | *When applied to an interface applies to all methods in the class 19 | * unless also applied to a method.
20 | * 21 | * @see java.sql.Statement#setFetchSize(int) 22 | * @see Fetch Size 23 | */ 24 | @Documented 25 | @Retention(RUNTIME) 26 | @Target({METHOD, TYPE}) 27 | public @interface FetchSize { 28 | 29 | /** 30 | * Sets the fetch size to be used. 31 | * 32 | *The usual disclaimers for setting the fetch size apply:
33 | *This class is used to extract a value object from every row in a 10 | * ref cursor out parameter.
11 | * 12 | *This class is modeled after Springs 13 | * {@link org.springframework.jdbc.core.RowMapper}. If you're using 14 | * lambdas the the code should directly port over. If not the easiest 15 | * way to bridge the code is using an method reference.
16 | * 17 | *Implementations should not catch {@link SQLException} this will 18 | * be done by a higher layer.
19 | * 20 | * @paramImplementations should not call {@link ResultSet#next()} but
31 | * instead expect to be called for every method.
32 | *
33 | * @param resultSet the ResultSet to the value of the current row from
34 | * @param rowNumber
35 | * the 0-based index of the current row, mostly for Spring compatibility
36 | * @return the value for the current row
37 | * @throws SQLException propagated if a method on {@link ResultSet} throws an exception
38 | * @see org.springframework.jdbc.core.RowMapper#mapRow(ResultSet, int)
39 | */
40 | V extractValue(ResultSet resultSet, int rowNumber) throws SQLException;
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/github/marschall/storedprocedureproxy/ToStringUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.marschall.storedprocedureproxy;
2 |
3 | import com.github.marschall.storedprocedureproxy.ProcedureCallerFactory.ProcedureCaller;
4 |
5 | final class ToStringUtils {
6 |
7 | private ToStringUtils() {
8 | throw new AssertionError("not instantiable");
9 | }
10 |
11 | static String fetchSizeToString(int fetchSize) {
12 | if (fetchSize == ProcedureCaller.DEFAULT_FETCH_SIZE) {
13 | return "default";
14 | } else {
15 | return Integer.toString(fetchSize);
16 | }
17 | }
18 |
19 | static String classNameToString(Class> clazz) {
20 | if (clazz.getPackage().getName().equals("java.lang")) {
21 | return clazz.getSimpleName();
22 | } else {
23 | return clazz.getName();
24 | }
25 | }
26 |
27 | static void toStringOn(String[] array, StringBuilder builder) {
28 | for (int i = 0; i < array.length; i++) {
29 | if (i > 0) {
30 | builder.append(", ");
31 | }
32 | String element = array[i];
33 | builder.append(element);
34 | }
35 | }
36 |
37 | static void toStringOn(Object[] array, StringBuilder builder) {
38 | for (int i = 0; i < array.length; i++) {
39 | if (i > 0) {
40 | builder.append(", ");
41 | }
42 | Object element = array[i];
43 | builder.append(element);
44 | }
45 | }
46 |
47 | static void toStringOn(int[] array, StringBuilder builder) {
48 | for (int i = 0; i < array.length; i++) {
49 | if (i > 0) {
50 | builder.append(", ");
51 | }
52 | int element = array[i];
53 | builder.append(element);
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/com/github/marschall/storedprocedureproxy/procedures/H2Procedures.java:
--------------------------------------------------------------------------------
1 | package com.github.marschall.storedprocedureproxy.procedures;
2 |
3 | import java.sql.ResultSet;
4 | import java.util.List;
5 | import java.util.function.Function;
6 |
7 | import com.github.marschall.storedprocedureproxy.NumberedValueExtractor;
8 | import com.github.marschall.storedprocedureproxy.ValueExtractor;
9 | import com.github.marschall.storedprocedureproxy.annotations.ReturnValue;
10 |
11 | public interface H2Procedures {
12 |
13 | @ReturnValue
14 | String stringProcedure(String input);
15 |
16 | void voidProcedure(String input);
17 |
18 | @ReturnValue
19 | String noArgProcedure();
20 |
21 | @ReturnValue
22 | Integer[] reverseIntegerArray(Integer[] input);
23 |
24 | @ReturnValue
25 | Integer[] returnIntegerArray();
26 |
27 | List Applied to a method means that the return value should be retrieved using an
15 | * inout parameter. Unlike {@link OutParameter} or {@link ReturnValue} most additional
18 | * information in taken from the method parameter Causes a call string to be generated in the form of
21 | * {@code {@code "{call function_name(?)}" instead of "{ ? = call function_name()}"}}
22 | * where one of the function arguments is an out parameter. If the out parameter isn't the last parameter you have to
38 | * provide the index of the out parameter. Also allows to provide additional information about the return value. You would use this for functions as opposed to procedures. Causes a call string to be generated in the form of
22 | * {@code "{ ? = call function_name()}"} instead of {@code "{call function_name(?)}"}. Applied to a method means that the return value should be retrieved using an
18 | * out parameter.
19 | * In addition allows to provide additional information about the out parameter. Causes a call string to be generated in the form of
22 | * {@code {@code "{call function_name(?)}" instead of "{ ? = call function_name()}"}}
23 | * where one of the function arguments is an out parameter. If the out parameter isn't the last parameter you have to
48 | * provide the index of the out parameter. The mapping defined by an instance of this class will be applied
14 | * globally to all in and out parameter of all methods in an interface.
15 | * If you want to customize only a single parameter use
16 | * {@link ParameterType}, {@link OutParameter#type()} or
17 | * {@link ReturnValue#type()} instead. If no custom implementation is specified the following default
20 | * are used: The behavior is: Provides various convenience methods for chaining several
9 | * implementations. For example if the Java name of your stored procedure
10 | * is {@code "blitz"} but the SQL name is {@code "sp_Blitz"} then you can
11 | * create this transformation using: Only works reliably for characters from the US-ASCII latin alphabet. Only works reliably for characters from the US-ASCII latin alphabet. Only works for characters from the US-ASCII latin alphabet. For example turns {@code "procedureName"} into {@code "procedure_Name"}.
74 | * No case conversion is done so you'll likely want to combine this with
75 | * either {@link #thenUpperCase()} or {@link #thenLowerCase()}. Only works reliably for characters from the US-ASCII latin alphabet. Only works reliably for characters from the US-ASCII latin alphabet. Only works for characters from the US-ASCII latin alphabet. For example turns {@code "procedureName"} into {@code "procedure_Name"}.
156 | * No case conversion is done so you'll likely want to combine this with
157 | * either {@link #thenUpperCase()} or {@link #thenLowerCase()}.
22 | *
75 | */
76 | @FunctionalInterface
77 | public interface TypeMapper {
78 |
79 | /**
80 | * Maps a Java type to a SQL type.
81 | *
82 | * @see java.sql.Types
83 | * @param javaType
84 | * the java type, may be a primitive type like {@code int.class},
85 | * never {@code null}, never {@code void.class}
86 | * @return the SQL type, may be a vendor type
87 | */
88 | int mapToSqlType(Class> javaType);
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/com/github/marschall/storedprocedureproxy/DefaultTypeNameResolver.java:
--------------------------------------------------------------------------------
1 | package com.github.marschall.storedprocedureproxy;
2 |
3 | import java.lang.reflect.Parameter;
4 | import java.lang.reflect.ParameterizedType;
5 | import java.lang.reflect.Type;
6 | import java.math.BigDecimal;
7 | import java.math.BigInteger;
8 | import java.time.LocalDate;
9 | import java.time.LocalDateTime;
10 | import java.time.LocalTime;
11 | import java.util.Collection;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 |
15 | import com.github.marschall.storedprocedureproxy.spi.TypeNameResolver;
16 |
17 | /**
18 | * Default implementation of {@link TypeNameResolver}.
19 | *
20 | *
24 | * Java Type SQL type
25 | * String {@link Types#VARCHAR}
26 | * char is not mapped
27 | * limited precision integers
28 | * Integer {@link Types#INTEGER}
29 | * int {@link Types#INTEGER}
30 | * Long {@link Types#BIGINT}
31 | * long {@link Types#BIGINT}
32 | * Short {@link Types#SMALLINT}
33 | * short {@link Types#SMALLINT}
34 | * Byte {@link Types#TINYINT}
35 | * byte {@link Types#TINYINT}
36 | * arbitrary precision numbers
37 | * should be an alias for DECIMAL but Oracle treats DECIMAL as double
38 | * BigDecimal {@link Types#NUMERIC}
39 |
40 | * BigInteger {@link Types#NUMERIC}
41 | * floating points
42 | * Float {@link Types#REAL}
43 | * Double {@link Types#DOUBLE}
44 | * float {@link Types#REAL}
45 |
46 | * double {@link Types#DOUBLE}
47 | * LOBs
48 | * Blob {@link Types#BLOB}
49 | * Clob {@link Types#CLOB}
50 |
51 | * NClob {@link Types#NCLOB}
52 | * java 8 date time
53 | * LocalDate {@link Types#DATE}
54 | * LocalTime {@link Types#TIME}
55 | * LocalDateTime {@link Types#TIMESTAMP}
56 | * OffsetTime {@link Types#TIME_WITH_TIMEZONE}
57 |
58 | * OffsetDateTime {@link Types#TIMESTAMP_WITH_TIMEZONE}
59 | * old date time
60 | * java.sql.Date {@link Types#DATE}
61 | * java.sql.Time {@link Types#TIME}
62 |
63 | * java.sql.Timestamp {@link Types#TIMESTAMP}
64 | * XML
65 | * SQLXML {@link Types#SQLXML}
66 | * boolean
67 | * Boolean {@link Types#BOOLEAN}
68 |
69 | * boolean {@link Types#BOOLEAN}
70 | * ARRAY
71 | * Collection {@link Types#ARRAY}
72 | * List {@link Types#ARRAY}
73 | * Set {@link Types#ARRAY}
74 | * array {@link Types#ARRAY}
22 | *
24 | *
25 | */
26 | final class DefaultTypeNameResolver implements TypeNameResolver {
27 |
28 | static final TypeNameResolver INSTANCE = new DefaultTypeNameResolver();
29 |
30 | private final Map
16 | *
17 | * @see Deriving Names
18 | */
19 | @FunctionalInterface
20 | public interface NamingStrategy {
21 |
22 | /**
23 | * The identity transformation. Simply returns the argument unchanged.
24 | */
25 | public static NamingStrategy IDENTITY = (s) -> s;
26 |
27 | /**
28 | * Derives a database name of an object from the Java name of an object.
29 | *
30 | * @param javaName the Java name of an object, never {@code null}
31 | * @return the database name of an object, never {@code null}
32 | */
33 | String translateToDatabase(String javaName);
34 |
35 | /**
36 | * Creates a new transformation that converts the entire string to upper case.
37 | *
38 | *
13 | * NamingStrategy.capitalize() // converts "blitz" to "Blitz"
14 | * .thenPrefix("sp_") // converts "Blitz" to "sp_Blitz"
15 | *