DATAJPA-652 - Added support for REF_CURSOR output parameters for stored procedures.
We now support detecting output parameters for stored-procedures with ParameterMode.REF_CURSOR. Previously we only considered parameters with OUT or INOUT mode as output parameters. Added additional test cases for various procedure definition options. Introduced new Dummy test type to avoid polluting the User test type anymore with additional procedure definitions. Added test for eclipse link and Openjpa but I had to deactivate them since they currently need to be run with HSQLDB V1 which doesn’t support stored procedures. Original pull request: #130.
This commit is contained in:
committed by
Oliver Gierke
parent
81e69ab65a
commit
a5f20d23ce
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2015 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.springframework.data.jpa.domain.sample;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Sample domain class representing used for Stored Procedure tests.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Entity
|
||||
@NamedStoredProcedureQueries({ //
|
||||
@NamedStoredProcedureQuery(name = "Dummy.procedureWith1InputAnd1OutputParameter",
|
||||
procedureName = "procedure_in1_out1", parameters = {
|
||||
@StoredProcedureParameter(mode = ParameterMode.IN, type = Integer.class),
|
||||
@StoredProcedureParameter(mode = ParameterMode.OUT, type = Integer.class) }) //
|
||||
,
|
||||
@NamedStoredProcedureQuery(name = "Dummy.procedureWith1InputAndNoOutputParameter",
|
||||
procedureName = "procedure_in1_out0", parameters = { @StoredProcedureParameter(mode = ParameterMode.IN,
|
||||
type = Integer.class) }) //
|
||||
,
|
||||
@NamedStoredProcedureQuery(name = "Dummy.procedureWithNoInputAnd1OutputParameter",
|
||||
procedureName = "procedure_in0_out1", parameters = { @StoredProcedureParameter(mode = ParameterMode.OUT,
|
||||
type = Integer.class) }) //
|
||||
,
|
||||
@NamedStoredProcedureQuery(name = "Dummy.procedureWith1InputAnd1OutputParameterWithResultSet",
|
||||
procedureName = "procedure_in1_out0_return_rs_no_update", parameters = {
|
||||
@StoredProcedureParameter(mode = ParameterMode.IN, type = Integer.class),
|
||||
@StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class) }) //
|
||||
,
|
||||
@NamedStoredProcedureQuery(name = "Dummy.procedureWith1InputAnd1OutputParameterWithResultSetWithUpdate",
|
||||
procedureName = "procedure_in1_out0_return_rs_with_update", parameters = {
|
||||
@StoredProcedureParameter(mode = ParameterMode.IN, type = Integer.class),
|
||||
@StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class) }) //
|
||||
,
|
||||
@NamedStoredProcedureQuery(name = "Dummy.procedureWith1InputAndNoOutputParameterWithUpdate",
|
||||
procedureName = "procedure_in1_out0_no_return_with_update", parameters = { @StoredProcedureParameter(
|
||||
mode = ParameterMode.IN, type = String.class) }) //
|
||||
})
|
||||
public class Dummy {
|
||||
|
||||
@Id @GeneratedValue private Integer id;
|
||||
private String name;
|
||||
|
||||
public Dummy() {}
|
||||
|
||||
public Dummy(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Dummy [id=" + id + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
|
||||
if (that == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(that instanceof Dummy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.name, ((Dummy) that).name);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2014 the original author or authors.
|
||||
* Copyright 2008-2015 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.
|
||||
@@ -84,7 +84,7 @@ public class User {
|
||||
@Lob private byte[] binaryData;
|
||||
|
||||
@ElementCollection private Set<String> attributes;
|
||||
|
||||
|
||||
@Temporal(TemporalType.DATE) private Date dateOfBirth;
|
||||
|
||||
/**
|
||||
@@ -367,7 +367,7 @@ public class User {
|
||||
public void setAttributes(Set<String> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
|
||||
public Date getDateOfBirth() {
|
||||
return dateOfBirth;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2008-2015 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.springframework.data.jpa.repository;
|
||||
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Testcase to run {@link StoredProcedureIntegrationTests} integration tests on top of EclipseLink.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@ContextConfiguration(classes = { StoredProcedureIntegrationTests.Config.class })
|
||||
@ImportResource("classpath:eclipselink.xml")
|
||||
public class EclipseLinkStoredProcedureIntegrationTests extends StoredProcedureIntegrationTests {}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2015 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.springframework.data.jpa.repository;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Test case to run {@link StoredProcedureIntegrationTests} integration tests on top of OpenJpa. This is currently not
|
||||
* supported since, the OpenJPA tests need to be executed with hsqldb1 which doesn't supported stored procedures.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Ignore
|
||||
@ContextConfiguration(classes = { StoredProcedureIntegrationTests.Config.class })
|
||||
@ImportResource("classpath:openjpa.xml")
|
||||
public class OpenJpaStoredProcedureIntegrationTests extends StoredProcedureIntegrationTests {}
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2015 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.springframework.data.jpa.repository;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.data.jpa.support.EntityManagerTestUtils.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.data.jpa.domain.sample.Dummy;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.jpa.repository.sample.DummyRepository;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @see scripts/schema-stored-procedures.sql for procedure definitions.
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Transactional
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class StoredProcedureIntegrationTests {
|
||||
|
||||
@PersistenceContext EntityManager em;
|
||||
@Autowired DummyRepository repository;
|
||||
|
||||
Dummy dummyA;
|
||||
Dummy dummyB;
|
||||
Dummy dummyC;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories(basePackageClasses = DummyRepository.class, includeFilters = { @Filter(
|
||||
pattern = ".*DummyRepository", type = FilterType.REGEX) })
|
||||
@ImportResource("classpath:infrastructure.xml")
|
||||
static class Config {}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
assumeTrue(currentEntityManagerIsAJpa21EntityManager(em));
|
||||
|
||||
dummyA = em.merge(new Dummy("A"));
|
||||
dummyB = em.merge(new Dummy("B"));
|
||||
dummyC = em.merge(new Dummy("C"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteAdHocProcedureWithNoInputAnd1OutputParameter() {
|
||||
assertThat(repository.adHocProcedureWithNoInputAnd1OutputParameter(), is(equalTo(42)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteAdHocProcedureWith1InputAnd1OutputParameter() {
|
||||
assertThat(repository.adHocProcedureWith1InputAnd1OutputParameter(23), is(equalTo(24)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteAdHocProcedureWith1InputAndNoOutputParameter() {
|
||||
|
||||
repository.adHocProcedureWith1InputAndNoOutputParameter(42);
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteAdHocProcedureWith1InputAnd1OutputParameterWithResultSet() {
|
||||
|
||||
// hibernate currently (v4.3) doesn't support returning ResultSets in output parameters
|
||||
assumeFalse(currentEntityManagerIsHibernateEntityManager(em));
|
||||
|
||||
List<Dummy> dummies = repository.adHocProcedureWith1InputAnd1OutputParameterWithResultSet("FOO");
|
||||
|
||||
System.out.println("### Found dummies: " + dummies);
|
||||
|
||||
assertThat(dummies, is(notNullValue()));
|
||||
assertThat(dummies.size(), is(equalTo(3)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteAdHocProcedureWith1InputAnd1OutputParameterWithResultSetWithUpdate() {
|
||||
|
||||
// hibernate currently (v4.3) doesn't support returning ResultSets in output parameters
|
||||
assumeFalse(currentEntityManagerIsHibernateEntityManager(em));
|
||||
|
||||
List<Dummy> dummies = repository.adHocProcedureWith1InputAnd1OutputParameterWithResultSetWithUpdate("FOO");
|
||||
|
||||
System.out.println("### Found dummies: " + dummies);
|
||||
|
||||
assertThat(dummies, is(notNullValue()));
|
||||
assertThat(dummies.size(), is(equalTo(3)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteAdHocProcedureWith1InputAnd1OutputParameterWithUpdate() {
|
||||
|
||||
repository.adHocProcedureWith1InputAndNoOutputParameterWithUpdate("FOO");
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteProcedureWithNoInputAnd1OutputParameter() {
|
||||
assertThat(repository.procedureWithNoInputAnd1OutputParameter(), is(equalTo(42)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteProcedureWith1InputAnd1OutputParameter() {
|
||||
assertThat(repository.procedureWith1InputAnd1OutputParameter(23), is(equalTo(24)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteProcedureWith1InputAndNoOutputParameter() {
|
||||
|
||||
repository.procedureWith1InputAndNoOutputParameter(42);
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteProcedureWith1InputAnd1OutputParameterWithResultSet() {
|
||||
|
||||
// hibernate currently (v4.3) doesn't support returning ResultSets in output parameters
|
||||
assumeFalse(currentEntityManagerIsHibernateEntityManager(em));
|
||||
|
||||
List<Dummy> dummies = repository.procedureWith1InputAnd1OutputParameterWithResultSet("FOO");
|
||||
|
||||
assertThat(dummies, is(notNullValue()));
|
||||
assertThat(dummies.size(), is(equalTo(3)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteProcedureWith1InputAnd1OutputParameterWithResultSetWithUpdate() {
|
||||
|
||||
// hibernate currently (v4.3) doesn't support returning ResultSets in output parameters
|
||||
assumeFalse(currentEntityManagerIsHibernateEntityManager(em));
|
||||
|
||||
List<Dummy> dummies = repository.procedureWith1InputAnd1OutputParameterWithResultSetWithUpdate("FOO");
|
||||
|
||||
assertThat(dummies, is(notNullValue()));
|
||||
assertThat(dummies.size(), is(equalTo(3)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-652
|
||||
*/
|
||||
@Test
|
||||
public void shouldExecuteProcedureWith1InputAnd1OutputParameterWithUpdate() {
|
||||
|
||||
repository.procedureWith1InputAndNoOutputParameterWithUpdate("FOO");
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2015 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.springframework.data.jpa.repository.sample;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.domain.sample.Dummy;
|
||||
import org.springframework.data.jpa.repository.query.Procedure;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public interface DummyRepository extends CrudRepository<Dummy, Long> {
|
||||
|
||||
@Procedure("procedure_in1_out1")
|
||||
Integer adHocProcedureWith1InputAnd1OutputParameter(Integer in);
|
||||
|
||||
@Procedure("procedure_in1_out0")
|
||||
void adHocProcedureWith1InputAndNoOutputParameter(Integer in);
|
||||
|
||||
@Procedure("procedure_in0_out1")
|
||||
Integer adHocProcedureWithNoInputAnd1OutputParameter();
|
||||
|
||||
@Procedure("procedure_in1_out0_return_rs_no_update")
|
||||
List<Dummy> adHocProcedureWith1InputAnd1OutputParameterWithResultSet(String in);
|
||||
|
||||
@Procedure("procedure_in1_out0_return_rs_with_update")
|
||||
List<Dummy> adHocProcedureWith1InputAnd1OutputParameterWithResultSetWithUpdate(String in);
|
||||
|
||||
@Procedure("procedure_in1_out0_no_return_with_update")
|
||||
void adHocProcedureWith1InputAndNoOutputParameterWithUpdate(String in);
|
||||
|
||||
@Procedure
|
||||
Integer procedureWith1InputAnd1OutputParameter(Integer in);
|
||||
|
||||
@Procedure
|
||||
void procedureWith1InputAndNoOutputParameter(Integer in);
|
||||
|
||||
@Procedure
|
||||
Integer procedureWithNoInputAnd1OutputParameter();
|
||||
|
||||
@Procedure
|
||||
List<Dummy> procedureWith1InputAnd1OutputParameterWithResultSet(String in);
|
||||
|
||||
@Procedure
|
||||
List<Dummy> procedureWith1InputAnd1OutputParameterWithResultSetWithUpdate(String in);
|
||||
|
||||
@Procedure
|
||||
void procedureWith1InputAndNoOutputParameterWithUpdate(String in);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 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.
|
||||
@@ -32,4 +32,8 @@ public abstract class EntityManagerTestUtils {
|
||||
return ReflectionUtils.findMethod(((org.springframework.orm.jpa.EntityManagerProxy) em).getTargetEntityManager()
|
||||
.getClass(), "getEntityGraph", String.class) != null;
|
||||
}
|
||||
|
||||
public static boolean currentEntityManagerIsHibernateEntityManager(EntityManager em) {
|
||||
return em.getDelegate().getClass().getName().toLowerCase().contains("hibernate");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user