INT-3150: JPA: Add support for max-results-expression
JIRA: https://jira.springsource.org/browse/INT-3150
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.integration.jpa.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
@@ -23,20 +25,17 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.jpa.inbound.JpaPollingChannelAdapter;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* The JPA Inbound Channel adapter parser
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser{
|
||||
|
||||
public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
|
||||
|
||||
@Override
|
||||
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
|
||||
|
||||
final BeanDefinitionBuilder jpaPollingChannelAdapterBuilder = BeanDefinitionBuilder
|
||||
@@ -44,7 +43,12 @@ public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChanne
|
||||
|
||||
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getJpaExecutorBuilder(element, parserContext);
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "max-number-of-results");
|
||||
BeanDefinition definition = IntegrationNamespaceUtils
|
||||
.createExpressionDefinitionFromValueOrExpression("max-number-of-results", "max-results-expression",
|
||||
parserContext, element, false);
|
||||
if (definition != null) {
|
||||
jpaExecutorBuilder.addPropertyValue("maxResultsExpression", definition);
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "delete-after-poll");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "delete-in-batch");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "expect-single-result");
|
||||
@@ -59,4 +63,5 @@ public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChanne
|
||||
|
||||
return jpaPollingChannelAdapterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.integration.jpa.config.xml;
|
||||
|
||||
import static org.springframework.integration.config.xml.IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -31,9 +29,7 @@ import org.springframework.integration.jpa.support.OutboundGatewayType;
|
||||
*
|
||||
* @author Amol Nayak
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class RetrievingJpaOutboundGatewayParser extends AbstractJpaOutboundGatewayParser {
|
||||
|
||||
@@ -44,14 +40,20 @@ public class RetrievingJpaOutboundGatewayParser extends AbstractJpaOutboundGatew
|
||||
|
||||
final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getOutboundGatewayJpaExecutorBuilder(gatewayElement, parserContext);
|
||||
|
||||
|
||||
BeanDefinition firstResultExpression = createExpressionDefinitionFromValueOrExpression("first-result",
|
||||
"first-result-expression", parserContext, gatewayElement, false);
|
||||
|
||||
if(firstResultExpression != null) {
|
||||
BeanDefinition firstResultExpression = IntegrationNamespaceUtils
|
||||
.createExpressionDefinitionFromValueOrExpression("first-result", "first-result-expression",
|
||||
parserContext, gatewayElement, false);
|
||||
if (firstResultExpression != null) {
|
||||
jpaExecutorBuilder.addPropertyValue("firstResultExpression", firstResultExpression);
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "max-number-of-results");
|
||||
|
||||
BeanDefinition maxResultsExpression = IntegrationNamespaceUtils
|
||||
.createExpressionDefinitionFromValueOrExpression("max-number-of-results", "max-results-expression",
|
||||
parserContext, gatewayElement, false);
|
||||
if (maxResultsExpression != null) {
|
||||
jpaExecutorBuilder.addPropertyValue("maxResultsExpression", maxResultsExpression);
|
||||
}
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-after-poll");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "delete-in-batch");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, gatewayElement, "expect-single-result");
|
||||
@@ -64,6 +66,8 @@ public class RetrievingJpaOutboundGatewayParser extends AbstractJpaOutboundGatew
|
||||
|
||||
jpaOutboundGatewayBuilder.addConstructorArgReference(jpaExecutorBeanName);
|
||||
jpaOutboundGatewayBuilder.addPropertyValue("gatewayType", OutboundGatewayType.RETRIEVING);
|
||||
|
||||
return jpaOutboundGatewayBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.expression.IntegrationEvaluationContextAware;
|
||||
@@ -65,7 +66,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class JpaExecutor implements InitializingBean, BeanFactoryAware, IntegrationEvaluationContextAware {
|
||||
|
||||
private volatile JpaOperations jpaOperations;
|
||||
private final JpaOperations jpaOperations;
|
||||
|
||||
private volatile List<JpaParameter> jpaParameters;
|
||||
|
||||
private volatile Class<?> entityClass;
|
||||
@@ -73,8 +75,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
private volatile String nativeQuery;
|
||||
private volatile String namedQuery;
|
||||
|
||||
/** 0 means all possible objects shall be retrieved. */
|
||||
private volatile int maxNumberOfResults = 0;
|
||||
private volatile Expression maxResultsExpression;
|
||||
|
||||
private volatile Expression firstResultExpression;
|
||||
|
||||
@@ -91,7 +92,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
/**
|
||||
* Indicates that whether only the payload of the passed in {@link Message}
|
||||
* will be used as a source of parameters. The is 'true' by default because as a
|
||||
* default a {@link BeanPropertyJpaParameterSourceFactory} implementation is
|
||||
* default a {@link BeanPropertyParameterSourceFactory} implementation is
|
||||
* used for the sqlParameterSourceFactory property.
|
||||
*/
|
||||
private volatile Boolean usePayloadAsParameterSource = null;
|
||||
@@ -163,7 +164,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
if (this.parameterSourceFactory == null) {
|
||||
ExpressionEvaluatingParameterSourceFactory expressionSourceFactory =
|
||||
new ExpressionEvaluatingParameterSourceFactory(this.beanFactory);
|
||||
expressionSourceFactory.setParameters(jpaParameters);
|
||||
expressionSourceFactory.setParameters(this.jpaParameters);
|
||||
this.parameterSourceFactory = expressionSourceFactory;
|
||||
|
||||
}
|
||||
@@ -192,9 +193,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
if (this.usePayloadAsParameterSource == null) {
|
||||
this.usePayloadAsParameterSource = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +205,8 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
* not necessarily correlate with the number of rows effected in the database.
|
||||
*
|
||||
* @param message
|
||||
* @return Either the number of affected entities when using a JPAQL query. When using a merge/persist the updated/inserted itself is returned.
|
||||
* @return Either the number of affected entities when using a JPQL query.
|
||||
* When using a merge/persist the updated/inserted itself is returned.
|
||||
*/
|
||||
public Object executeOutboundJpaOperation(final Message<?> message) {
|
||||
|
||||
@@ -214,22 +214,16 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
|
||||
ParameterSource parameterSource = null;
|
||||
if (this.jpaQuery != null || this.nativeQuery != null || this.namedQuery != null) {
|
||||
parameterSource = determineParameterSource(message);
|
||||
parameterSource = this.determineParameterSource(message);
|
||||
}
|
||||
if (this.jpaQuery != null) {
|
||||
|
||||
result = this.jpaOperations.executeUpdate(this.jpaQuery, parameterSource);
|
||||
|
||||
}
|
||||
else if (this.nativeQuery != null) {
|
||||
|
||||
result = this.jpaOperations.executeUpdateWithNativeQuery(this.nativeQuery, parameterSource);
|
||||
|
||||
}
|
||||
else if (this.namedQuery != null) {
|
||||
|
||||
result = this.jpaOperations.executeUpdateWithNamedQuery(this.namedQuery, parameterSource);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -238,8 +232,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
result = message.getPayload();
|
||||
}
|
||||
else if (PersistMode.MERGE.equals(this.persistMode)) {
|
||||
final Object mergedEntity = this.jpaOperations.merge(message.getPayload());
|
||||
result = mergedEntity;
|
||||
result = this.jpaOperations.merge(message.getPayload());
|
||||
}
|
||||
else if (PersistMode.DELETE.equals(this.persistMode)) {
|
||||
this.jpaOperations.delete(message.getPayload());
|
||||
@@ -270,16 +263,17 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
public Object poll(final Message<?> requestMessage) {
|
||||
final Object payload;
|
||||
final List<?> result;
|
||||
int maxNumberOfResults = this.evaluateExpressionForNumericResult(requestMessage, this.maxResultsExpression);
|
||||
if (requestMessage == null) {
|
||||
result = doPoll(this.parameterSource, 0);
|
||||
result = this.doPoll(this.parameterSource, 0, maxNumberOfResults);
|
||||
}
|
||||
else {
|
||||
int firstResult = 0;
|
||||
if(firstResultExpression != null) {
|
||||
firstResult = getFirstResult(requestMessage);
|
||||
firstResult = this.getFirstResult(requestMessage);
|
||||
}
|
||||
ParameterSource parameterSource = determineParameterSource(requestMessage);
|
||||
result = doPoll(parameterSource, firstResult);
|
||||
ParameterSource parameterSource = this.determineParameterSource(requestMessage);
|
||||
result = this.doPoll(parameterSource, firstResult, maxNumberOfResults);
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
@@ -293,8 +287,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
}
|
||||
else {
|
||||
throw new MessagingException(requestMessage,
|
||||
"The Jpa operation returned more than "
|
||||
+ "1 result object but expectSingleResult was 'true'.");
|
||||
"The Jpa operation returned more than 1 result object but expectSingleResult was 'true'.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -322,28 +315,34 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
}
|
||||
|
||||
private int getFirstResult(final Message<?> requestMessage) {
|
||||
int firstResult = 0;
|
||||
Object firstRecordEvaluationResult = firstResultExpression.getValue(evaluationContext, requestMessage);
|
||||
if(firstRecordEvaluationResult != null) {
|
||||
if(firstRecordEvaluationResult instanceof Number) {
|
||||
firstResult = ((Number)firstRecordEvaluationResult).intValue();
|
||||
}
|
||||
else if(firstRecordEvaluationResult instanceof String){
|
||||
try {
|
||||
firstResult = Integer.parseInt((String)firstRecordEvaluationResult);
|
||||
return this.evaluateExpressionForNumericResult(requestMessage, this.firstResultExpression);
|
||||
}
|
||||
|
||||
private int evaluateExpressionForNumericResult(final Message<?> requestMessage, Expression expression) {
|
||||
int evaluatedResult = 0;
|
||||
if(expression != null) {
|
||||
Object evaluationResult = expression.getValue(this.evaluationContext, requestMessage);
|
||||
if(evaluationResult != null) {
|
||||
if(evaluationResult instanceof Number) {
|
||||
evaluatedResult = ((Number) evaluationResult).intValue();
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Value " + firstRecordEvaluationResult + " passed as firstRecord cannot be " +
|
||||
"parsed to a number");
|
||||
else if(evaluationResult instanceof String){
|
||||
try {
|
||||
evaluatedResult = Integer.parseInt((String) evaluationResult);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Value " + evaluationResult + " passed as cannot be " +
|
||||
"parsed to a number, expected to be numeric");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Expected the value to be a Number" +
|
||||
" got " + evaluationResult.getClass().getName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Expected the value of the firstRecord to be a Number" +
|
||||
" got " + firstRecordEvaluationResult.getClass().getName());
|
||||
}
|
||||
}
|
||||
return firstResult;
|
||||
return evaluatedResult;
|
||||
}
|
||||
|
||||
private ParameterSource determineParameterSource(final Message<?> requestMessage) {
|
||||
@@ -361,26 +360,25 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
* Execute the JPA operation. Delegates to {@link JpaExecutor#poll(Message)}.
|
||||
*/
|
||||
public Object poll() {
|
||||
return poll(null);
|
||||
return this.poll(null);
|
||||
}
|
||||
|
||||
protected List<?> doPoll(ParameterSource jpaQLParameterSource, int firstResult) {
|
||||
protected List<?> doPoll(ParameterSource jpaQLParameterSource, int firstResult, int maxNumberOfResults) {
|
||||
List<?> payload = null;
|
||||
if (this.jpaQuery != null) {
|
||||
payload = jpaOperations.getResultListForQuery(this.jpaQuery, jpaQLParameterSource,
|
||||
payload = this.jpaOperations.getResultListForQuery(this.jpaQuery, jpaQLParameterSource,
|
||||
firstResult, maxNumberOfResults);
|
||||
}
|
||||
else if (this.nativeQuery != null) {
|
||||
payload = jpaOperations.getResultListForNativeQuery(this.nativeQuery, this.entityClass, jpaQLParameterSource,
|
||||
payload = this.jpaOperations.getResultListForNativeQuery(this.nativeQuery, this.entityClass, jpaQLParameterSource,
|
||||
firstResult, maxNumberOfResults);
|
||||
}
|
||||
else if (this.namedQuery != null) {
|
||||
payload = jpaOperations.getResultListForNamedQuery(this.namedQuery, jpaQLParameterSource,
|
||||
payload = this.jpaOperations.getResultListForNamedQuery(this.namedQuery, jpaQLParameterSource,
|
||||
firstResult, maxNumberOfResults);
|
||||
}
|
||||
else if (this.entityClass != null) {
|
||||
payload = jpaOperations.getResultListForClass(this.entityClass,
|
||||
firstResult, maxNumberOfResults);
|
||||
payload = this.jpaOperations.getResultListForClass(this.entityClass, firstResult, maxNumberOfResults);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("For the polling operation, one of "
|
||||
@@ -422,7 +420,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
public void setNativeQuery(String nativeQuery) {
|
||||
|
||||
Assert.isTrue(this.namedQuery == null && this.jpaQuery == null, "You can define only one of the "
|
||||
+ "properties 'jpaQuery', 'nativeQuery', 'namedQuery'");;
|
||||
+ "properties 'jpaQuery', 'nativeQuery', 'namedQuery'");
|
||||
Assert.hasText(nativeQuery, "nativeQuery must neither be null nor empty.");
|
||||
|
||||
this.nativeQuery = nativeQuery;
|
||||
@@ -490,8 +488,7 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
*
|
||||
* @param parameterSourceFactory Must not be null
|
||||
*/
|
||||
public void setParameterSourceFactory(
|
||||
ParameterSourceFactory parameterSourceFactory) {
|
||||
public void setParameterSourceFactory(ParameterSourceFactory parameterSourceFactory) {
|
||||
Assert.notNull(parameterSourceFactory, "parameterSourceFactory must not be null.");
|
||||
this.parameterSourceFactory = parameterSourceFactory;
|
||||
}
|
||||
@@ -526,19 +523,6 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
this.expectSingleResult = expectSingleResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max number of results to retrieve from the database. Defaults to
|
||||
* 0, which means that all possible objects shall be retrieved.
|
||||
*
|
||||
* @param maxNumberOfResults Must not be negative.
|
||||
*
|
||||
* @see Query#setMaxResults(int)
|
||||
*/
|
||||
public void setMaxNumberOfResults(int maxNumberOfResults) {
|
||||
Assert.isTrue(maxNumberOfResults >= 0, "maxNumberOfResults must not be negative.");
|
||||
this.maxNumberOfResults = maxNumberOfResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression that will be evaluated to get the first result in the query executed.
|
||||
* If a null expression is set, all the results in the result set will be retrieved
|
||||
@@ -552,6 +536,30 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets the expression for maximum number of results expression. It has be a non null value
|
||||
* Not setting one will default to the behavior of fetching all the records
|
||||
*
|
||||
* @param maxResultsExpression
|
||||
*/
|
||||
public void setMaxResultsExpression(Expression maxResultsExpression) {
|
||||
Assert.notNull(maxResultsExpression, "maxResultsExpression cannot be null");
|
||||
this.maxResultsExpression = maxResultsExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max number of results to retrieve from the database. Defaults to
|
||||
* 0, which means that all possible objects shall be retrieved.
|
||||
*
|
||||
* @param maxNumberOfResults Must not be negative.
|
||||
*
|
||||
* @see Query#setMaxResults(int)
|
||||
*/
|
||||
public void setMaxNumberOfResults(int maxNumberOfResults) {
|
||||
this.setMaxResultsExpression(new LiteralExpression("" + maxNumberOfResults));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the evaluation context for evaluating the expression to get the from record of the
|
||||
* result set retrieved by the retrieving gateway.
|
||||
@@ -559,8 +567,8 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware, Integrat
|
||||
* @param evaluationContext
|
||||
*/
|
||||
@Override
|
||||
public void setIntegrationEvaluationContext(
|
||||
EvaluationContext evaluationContext) {
|
||||
public void setIntegrationEvaluationContext(EvaluationContext evaluationContext) {
|
||||
this.evaluationContext = evaluationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ public interface JpaOperations {
|
||||
*
|
||||
* @param query Must not be null or empty
|
||||
* @param firstResult The first result
|
||||
* @param maxNumberOfResults Must be a non-negative value
|
||||
* @param maxNumberOfResults Must be a non-negative value, any negative or zero will be ignored
|
||||
* @param source the Parameter source for this query to be executed, if none then set null
|
||||
* @return List of found entities
|
||||
*/
|
||||
|
||||
@@ -419,10 +419,21 @@
|
||||
<xsd:documentation>
|
||||
Specifies the maximum number of entities that shall be returned
|
||||
by a JPA Operation. Using this attribute you basically set
|
||||
the 'maxResults' property of the JPA Query object.
|
||||
the 'maxResults' property of the JPA Query object. This attribute is mutually
|
||||
exclusive to max-results-expression attribute.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="max-results-expression">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specifies the expression for the maximum number of entities that shall be returned
|
||||
by a JPA Operation. Using this attribute you basically set
|
||||
the 'maxResults' property of the JPA Query object. This attribute is mutually
|
||||
exclusive to max-number-of-results attribute.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expect-single-result" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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
|
||||
@@ -19,8 +19,11 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||
import org.springframework.integration.jpa.core.JpaExecutor;
|
||||
@@ -29,6 +32,8 @@ import org.springframework.integration.test.util.TestUtils;
|
||||
|
||||
/**
|
||||
* @author Gunnar Hillert
|
||||
* @author Amol Nayak
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@@ -84,10 +89,44 @@ public class JpaInboundChannelAdapterParserTests {
|
||||
|
||||
assertNotNull(jpaOperations);
|
||||
|
||||
assertEquals(Integer.valueOf(13), TestUtils.getPropertyValue(jpaExecutor, "maxNumberOfResults", Integer.class));
|
||||
LiteralExpression expression = TestUtils.getPropertyValue(jpaExecutor, "maxResultsExpression", LiteralExpression.class);
|
||||
|
||||
assertNotNull(expression);
|
||||
|
||||
assertEquals("13", TestUtils.getPropertyValue(expression, "literalValue"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJpaInboundChannelAdapterParserWithMaxResultsExpression() throws Exception {
|
||||
|
||||
setUp("JpaInboundChannelAdapterParserTests.xml", getClass(), "jpaInboundChannelAdapter3");
|
||||
|
||||
final AbstractMessageChannel outputChannel = TestUtils.getPropertyValue(this.consumer, "outputChannel", AbstractMessageChannel.class);
|
||||
|
||||
assertEquals("out", outputChannel.getComponentName());
|
||||
|
||||
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "source.jpaExecutor", JpaExecutor.class);
|
||||
|
||||
assertNotNull(jpaExecutor);
|
||||
|
||||
final Class<?> entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class);
|
||||
|
||||
assertEquals("org.springframework.integration.jpa.test.entity.StudentDomain", entityClass.getName());
|
||||
|
||||
final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class);
|
||||
|
||||
assertNotNull(jpaOperations);
|
||||
|
||||
SpelExpression expression = TestUtils.getPropertyValue(jpaExecutor, "maxResultsExpression", SpelExpression.class);
|
||||
|
||||
assertNotNull(expression);
|
||||
|
||||
assertEquals("@maxNumberOfResults", TestUtils.getPropertyValue(expression, "expression"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testJpaExecutorBeanIdNaming() throws Exception {
|
||||
|
||||
|
||||
@@ -28,5 +28,16 @@
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
|
||||
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter3"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
max-results-expression="@maxNumberOfResults"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<bean name="maxNumberOfResults" class="java.lang.Integer">
|
||||
<constructor-arg value="2"/>
|
||||
</bean>
|
||||
</beans>
|
||||
|
||||
@@ -76,8 +76,10 @@ public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice
|
||||
final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class);
|
||||
assertNotNull(jpaOperations);
|
||||
assertTrue(TestUtils.getPropertyValue(jpaExecutor, "expectSingleResult", Boolean.class));
|
||||
final Integer maxNumberOfResults = TestUtils.getPropertyValue(jpaExecutor, "maxNumberOfResults", Integer.class);
|
||||
assertEquals(Integer.valueOf(55), maxNumberOfResults);
|
||||
final LiteralExpression maxResultsExpression =
|
||||
TestUtils.getPropertyValue(jpaExecutor, "maxResultsExpression", LiteralExpression.class);
|
||||
assertNotNull(maxResultsExpression);
|
||||
assertEquals("55", TestUtils.getPropertyValue(maxResultsExpression, "literalValue"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -102,6 +104,17 @@ public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice
|
||||
assertEquals("header['firstResult']", TestUtils.getPropertyValue(firstResultExpression, "expression", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrievingJpaOutboundGatewayParserWithMaxResultExpression() throws Exception {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "retrievingJpaOutboundGatewayWithMaxResultExpression");
|
||||
final JpaOutboundGateway jpaOutboundGateway = TestUtils.getPropertyValue(this.consumer, "handler", JpaOutboundGateway.class);
|
||||
Expression maxNumberOfResultExpression =
|
||||
TestUtils.getPropertyValue(jpaOutboundGateway, "jpaExecutor.maxResultsExpression", Expression.class);
|
||||
assertNotNull(maxNumberOfResultExpression);
|
||||
assertEquals(SpelExpression.class, maxNumberOfResultExpression.getClass());
|
||||
assertEquals("header['maxResults']", TestUtils.getPropertyValue(maxNumberOfResultExpression, "expression", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatingJpaOutboundGatewayParser() throws Exception {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "updatingJpaOutboundGateway");
|
||||
|
||||
@@ -18,19 +18,18 @@
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
order="1"
|
||||
max-number-of-results="55"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
expect-single-result="true"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGatewayWithFirstResult"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
order="1"
|
||||
first-result="1"
|
||||
max-number-of-results="55"
|
||||
@@ -39,11 +38,22 @@
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGatewayWithMaxResultExpression"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
order="1"
|
||||
first-result="1"
|
||||
max-results-expression="header['maxResults']"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGatewayWithFirstResultExpression"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
order="1"
|
||||
first-result-expression="header['firstResult']"
|
||||
max-number-of-results="55"
|
||||
@@ -52,20 +62,6 @@
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGatewayWithExpressionExecutor"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="true"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
order="1"
|
||||
first-result-expression="header['firstResult']"
|
||||
max-number-of-results="55"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
|
||||
<int-jpa:updating-outbound-gateway id="updatingJpaOutboundGateway"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
auto-startup="false"
|
||||
|
||||
@@ -538,4 +538,11 @@ public class AbstractJpaOperationsTests {
|
||||
List<?> results = jpaOperations.getResultListForQuery(query, null, 2, 0);
|
||||
assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
public void testWithNegativeMaxNumberofResults() {
|
||||
JpaOperations jpaOperations = getJpaOperations(entityManager);
|
||||
String query = "select s from Student s";
|
||||
List<?> results = jpaOperations.getResultListForQuery(query, null, 0, -1);
|
||||
assertEquals(3, results.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.jpa.support.JpaParameter;
|
||||
import org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory;
|
||||
@@ -52,6 +53,8 @@ public class JpaExecutorTests {
|
||||
@Autowired
|
||||
protected EntityManager entityManager;
|
||||
|
||||
private final StandardEvaluationContext ctx = new StandardEvaluationContext();
|
||||
|
||||
/**
|
||||
* In this test, the {@link JpaExecutor}'s poll method will be called without
|
||||
* specifying a 'query', 'namedQuery' or 'entityClass' property. This should
|
||||
@@ -63,7 +66,7 @@ public class JpaExecutorTests {
|
||||
public void testExecutePollWithNoEntityClassSpecified() throws Exception {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(mock(EntityManager.class));
|
||||
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
try {
|
||||
jpaExecutor.poll();
|
||||
} catch (IllegalStateException e) {
|
||||
@@ -210,27 +213,12 @@ public class JpaExecutorTests {
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegativeMaxNumberOfResults() throws Exception {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(mock(EntityManager.class));
|
||||
|
||||
try {
|
||||
jpaExecutor.setMaxNumberOfResults(-10);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Assert.assertEquals("maxNumberOfResults must not be negative.", e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.fail("Was expecting an IllegalStateException to be thrown.");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultStartingFromThirdRecordForJPAQuery() throws Exception {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setJpaQuery("select s from Student s");
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.setIntegrationEvaluationContext(ctx);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
@@ -243,6 +231,7 @@ public class JpaExecutorTests {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setNativeQuery("select * from Student s");
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.setIntegrationEvaluationContext(ctx);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
Assert.assertNotNull(results);
|
||||
@@ -254,6 +243,7 @@ public class JpaExecutorTests {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setNamedQuery("selectAllStudents");
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.setIntegrationEvaluationContext(ctx);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
Assert.assertNotNull(results);
|
||||
@@ -265,9 +255,22 @@ public class JpaExecutorTests {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setEntityClass(StudentDomain.class);
|
||||
jpaExecutor.setFirstResultExpression(new LiteralExpression("2"));
|
||||
jpaExecutor.setIntegrationEvaluationContext(ctx);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
List<?> results = (List<?>)jpaExecutor.poll(MessageBuilder.withPayload("").build());
|
||||
Assert.assertNotNull(results);
|
||||
Assert.assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNullMaxResultsExpression() {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(mock(EntityManager.class));
|
||||
try {
|
||||
jpaExecutor.setMaxResultsExpression(null);
|
||||
} catch (Exception e) {
|
||||
Assert.assertEquals("maxResultsExpression cannot be null", e.getMessage());
|
||||
return;
|
||||
}
|
||||
Assert.fail("Expected the test case to throw an exception");
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,11 @@ import javax.persistence.EntityManager;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
|
||||
@@ -94,6 +96,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setEntityClass(StudentDomain.class);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
@@ -137,6 +140,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setJpaQuery("from Student");
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
@@ -180,7 +184,8 @@ public class JpaPollingChannelAdapterTests {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setJpaQuery("from Student");
|
||||
jpaExecutor.setMaxNumberOfResults(1);
|
||||
jpaExecutor.setMaxResultsExpression(new LiteralExpression("1"));
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
@@ -224,7 +229,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setJpaQuery("from Student s where s.firstName = 'First Two'");
|
||||
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
final SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter(
|
||||
@@ -273,6 +278,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
jpaExecutor.setJpaQuery("from Student s");
|
||||
jpaExecutor.setDeleteAfterPoll(true);
|
||||
jpaExecutor.setDeleteInBatch(true);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
@@ -332,6 +338,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setJpaQuery("from Student s where s.lastName = 'Something Else'");
|
||||
jpaExecutor.setDeleteAfterPoll(true);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
@@ -371,6 +378,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
jpaExecutor.setJpaQuery("from Student s");
|
||||
jpaExecutor.setDeleteAfterPoll(true);
|
||||
jpaExecutor.setDeleteInBatch(false);
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
@@ -417,6 +425,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setNativeQuery("select * from Student where lastName = 'Last One'");
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
@@ -460,6 +469,7 @@ public class JpaPollingChannelAdapterTests {
|
||||
|
||||
final JpaExecutor jpaExecutor = new JpaExecutor(entityManager);
|
||||
jpaExecutor.setNamedQuery("selectStudent");
|
||||
jpaExecutor.afterPropertiesSet();
|
||||
|
||||
final JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor);
|
||||
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
first-result-expression="payload"
|
||||
max-results-expression="headers['maxResults']"
|
||||
reply-timeout="100"/>
|
||||
</beans>
|
||||
|
||||
@@ -54,11 +54,11 @@ public class JpaOutboundGatewayIntegrationTests {
|
||||
|
||||
/**
|
||||
* Sends a message with the payload as a integer representing the start number in the result
|
||||
* set.
|
||||
* set and a header with value maxResults to get the max number of results
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void retrieveFromSecondRecord() throws Exception {
|
||||
public void retrieveFromSecondRecordAndMaximumOneRecord() throws Exception {
|
||||
responseChannel.subscribe(new MessageHandler() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
@@ -66,7 +66,10 @@ public class JpaOutboundGatewayIntegrationTests {
|
||||
assertEquals(1, ((List)message.getPayload()).size());
|
||||
}
|
||||
});
|
||||
Message<Integer> message = MessageBuilder.withPayload(2).build();
|
||||
Message<Integer> message = MessageBuilder
|
||||
.withPayload(1)
|
||||
.setHeader("maxResults", "1")
|
||||
.build();
|
||||
requestChannel.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<int:method name="getStudent2" request-channel="retrievingGatewayInsideChain" />
|
||||
<int:method name="persistStudent2" request-channel="updatingGatewayInsideChain" />
|
||||
<int:method name="getAllStudentsFromGivenRecord" request-channel="getStudentsFromGivenRecordChannel"/>
|
||||
<int:method name="getStudents" request-channel="getStudentsWithMaxNumberOfRecordsChannel"/>
|
||||
</int:gateway>
|
||||
|
||||
<int:channel id="studentReplyChannel"/>
|
||||
@@ -45,6 +46,7 @@
|
||||
<int:channel id="retrievingGatewayInsideChain"/>
|
||||
<int:channel id="updatingGatewayInsideChain"/>
|
||||
<int:channel id="getStudentsFromGivenRecordChannel"/>
|
||||
<int:channel id="getStudentsWithMaxNumberOfRecordsChannel"/>
|
||||
|
||||
<bean id="deleteStudentEndpoint"
|
||||
class="org.springframework.integration.endpoint.EventDrivenConsumer">
|
||||
@@ -220,6 +222,29 @@
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="getStudentsWithMaxNumberOfRecords"
|
||||
class="org.springframework.integration.endpoint.EventDrivenConsumer">
|
||||
<constructor-arg name="inputChannel" ref="getStudentsWithMaxNumberOfRecordsChannel"/>
|
||||
<constructor-arg name="handler">
|
||||
<bean class="org.springframework.integration.jpa.outbound.JpaOutboundGateway">
|
||||
<constructor-arg name="jpaExecutor">
|
||||
<bean class="org.springframework.integration.jpa.core.JpaExecutor">
|
||||
<constructor-arg name="entityManager" ref="entityManager"/>
|
||||
<property name="jpaQuery" value="select s from Student s"/>
|
||||
<property name="expectSingleResult" value="false"/>
|
||||
<property name="firstResultExpression"
|
||||
value="#{new org.springframework.expression.spel.standard.SpelExpressionParser().parseExpression('payload')}"/>
|
||||
<property name="maxResultsExpression"
|
||||
value="#{new org.springframework.expression.spel.standard.SpelExpressionParser().parseExpression('payload')}"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<property name="gatewayType" value="RETRIEVING"/>
|
||||
<property name="outputChannel" ref="studentReplyChannel"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
|
||||
<int:chain input-channel="retrievingGatewayInsideChain" output-channel="studentReplyChannel">
|
||||
<jpa:retrieving-outbound-gateway entity-manager="entityManager"
|
||||
expect-single-result="true"
|
||||
|
||||
@@ -67,6 +67,14 @@ public class JpaOutboundGatewayTests {
|
||||
Assert.assertEquals(2, students.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllStudentsWithMaxNumberOfRecords() {
|
||||
List<?> students = studentService.getStudents(1);
|
||||
Assert.assertNotNull(students);
|
||||
Assert.assertEquals(1, students.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void deleteNonExistingStudent() {
|
||||
|
||||
|
||||
@@ -40,4 +40,6 @@ public interface StudentService {
|
||||
StudentDomain getStudent2(Long id);
|
||||
|
||||
StudentDomain persistStudent2(StudentDomain studentToPersist);
|
||||
|
||||
List<StudentDomain> getStudents(int maxNumberOfRecords);
|
||||
}
|
||||
|
||||
@@ -408,6 +408,8 @@
|
||||
auto-startup="true" ]]><co id="inboundAdapterAutoStartup"/><![CDATA[
|
||||
query="select s from Student s" ]]><co id="inboundAdapterQuery"/><![CDATA[
|
||||
expect-single-result="true" ]]><co id="inboundAdapterExpectResult"/><![CDATA[
|
||||
max-number-of-results="" ]]><co id="inboundAdapterMaxResults"/><![CDATA[
|
||||
max-results-expression="" ]]><co id="inboundAdapterMaxResultsExpression"/><![CDATA[
|
||||
delete-after-poll="true"> ]]><co id="inboundAdapterDeleteAfterPoll"/><![CDATA[
|
||||
<int:poller fixed-rate="2000" >
|
||||
<int:transactional propagation="REQUIRED" transaction-manager="transactionManager"/>
|
||||
@@ -449,6 +451,21 @@
|
||||
<classname>MessagingException</classname> is thrown. The value defaults to <code>false</code>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="inboundAdapterMaxResults">
|
||||
<para>
|
||||
This non zero, non negative integer value tells the adapter not to select more than given number
|
||||
of rows on execution of the select operation. By default, if this attribute is not set,
|
||||
all the possible records are selected by given query. This attribute is mutually exclusive to
|
||||
<code>max-results-expression</code>. <emphasis>Optional</emphasis>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="inboundAdapterMaxResultsExpression">
|
||||
<para>
|
||||
An expression mutually exclusive to <code>max-number-of-results</code> that can
|
||||
be used to provide an expression that will be evaluated to find the maximum number of results
|
||||
in a result set. <emphasis>Optional</emphasis>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="inboundAdapterDeleteAfterPoll">
|
||||
<para>
|
||||
Set this value to <code>true</code> if you want
|
||||
@@ -1138,6 +1155,7 @@ public class Student {
|
||||
jpa-operations=""
|
||||
jpa-query=""
|
||||
max-number-of-results="" ]]><co id="outGateMaxNumOfResults"/><![CDATA[
|
||||
max-results-expression="" ]]><co id="outGateMaxNumOfResultsExpression"/><![CDATA[
|
||||
first-result="" ]]><co id="outGateFirstResult"/><![CDATA[
|
||||
first-result-expression="" ]]><co id="outGateFirstResultExpression"/><![CDATA[
|
||||
named-query=""
|
||||
@@ -1167,7 +1185,15 @@ public class Student {
|
||||
<para>
|
||||
This non zero, non negative integer value tells the adapter not to select more than given number
|
||||
of rows on execution of the select operation. By default, if this attribute is not set,
|
||||
all the possible records are selected by given query.<emphasis>Optional</emphasis>.
|
||||
all the possible records are selected by given query. This attribute is mutually exclusive to
|
||||
<code>max-results-expression</code>. <emphasis>Optional</emphasis>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outGateMaxNumOfResultsExpression">
|
||||
<para>
|
||||
An expression mutually exclusive to <code>max-number-of-results</code> that can
|
||||
be used to provide an expression that will be evaluated to find the maximum number of results
|
||||
in a result set. <emphasis>Optional</emphasis>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="outGateFirstResult">
|
||||
@@ -1319,4 +1345,4 @@ public class Student {
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -471,7 +471,17 @@
|
||||
Retrieving gateways had no mechanism to specify the first record to be retrieved which
|
||||
is a common use case. The retrieving gateways now support specifying this parameter
|
||||
using a <code>first-result</code> and <code>first-result-expression</code> attributes
|
||||
to the gateway definition.<xref linkend="jpa-retrieving-outbound-gateway"/>
|
||||
to the gateway definition. <xref linkend="jpa-retrieving-outbound-gateway"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="3.0-jpa-max-results">
|
||||
<title>JPA Adapters: max-results-expression attribute</title>
|
||||
<para>
|
||||
Retrieving gateways and inbound adapters now has a flexibility to specify the maximum
|
||||
number of results in a result set as an expression. We now have <code>max-number-of-results</code>
|
||||
and <code>max-results-expression</code> attributes which are used to provide the
|
||||
maximum number of results and the expression to compute the maximum number of results in the
|
||||
result set respectively. For more information see <xref linkend="jpa"/>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user