GH-3194: Add generics to Amqp and Jms channel impls

Fixes https://github.com/spring-projects/spring-integration/issues/3194

For now we keep the hierarchy, but try to generalize channel specs
a bit, so that ones who use `publishSubscribeChannel` can count on
`BroadcastCapableChannel` as interface to utilize.
This commit is contained in:
Artem Vozhdayenko
2020-09-25 21:55:10 +03:00
committed by GitHub
parent a8430c12a6
commit d75dd095a3
9 changed files with 51 additions and 30 deletions

View File

@@ -22,6 +22,7 @@ import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.integration.amqp.channel.PollableAmqpChannel;
import org.springframework.integration.amqp.inbound.AmqpMessageSource.AmqpAckCallbackFactory;
import org.springframework.lang.Nullable;
@@ -30,6 +31,7 @@ import org.springframework.lang.Nullable;
*
* @author Artem Bilan
* @author Gary Russell
* @author Artem Vozhdayenko
*
* @since 5.0
*/
@@ -269,7 +271,7 @@ public final class Amqp {
* @param connectionFactory the connectionFactory.
* @return the AmqpPollableMessageChannelSpec.
*/
public static AmqpPollableMessageChannelSpec<?> pollableChannel(ConnectionFactory connectionFactory) {
public static AmqpPollableMessageChannelSpec<?, PollableAmqpChannel> pollableChannel(ConnectionFactory connectionFactory) {
return pollableChannel(null, connectionFactory);
}
@@ -279,11 +281,11 @@ public final class Amqp {
* @param connectionFactory the connectionFactory.
* @return the AmqpPollableMessageChannelSpec.
*/
public static AmqpPollableMessageChannelSpec<?> pollableChannel(@Nullable String id,
public static AmqpPollableMessageChannelSpec<?, PollableAmqpChannel> pollableChannel(@Nullable String id,
ConnectionFactory connectionFactory) {
return new AmqpPollableMessageChannelSpec<>(connectionFactory)
.id(id);
AmqpPollableMessageChannelSpec<?, PollableAmqpChannel> spec = new AmqpPollableMessageChannelSpec<>(connectionFactory);
return spec.id(id);
}
/**
@@ -291,7 +293,7 @@ public final class Amqp {
* @param connectionFactory the connectionFactory.
* @return the AmqpMessageChannelSpec.
*/
public static AmqpMessageChannelSpec<?> channel(ConnectionFactory connectionFactory) {
public static AmqpMessageChannelSpec<?, ?> channel(ConnectionFactory connectionFactory) {
return channel(null, connectionFactory);
}
@@ -301,7 +303,7 @@ public final class Amqp {
* @param connectionFactory the connectionFactory.
* @return the AmqpMessageChannelSpec.
*/
public static AmqpMessageChannelSpec<?> channel(@Nullable String id, ConnectionFactory connectionFactory) {
public static AmqpMessageChannelSpec<?, ?> channel(@Nullable String id, ConnectionFactory connectionFactory) {
return new AmqpMessageChannelSpec<>(connectionFactory)
.id(id);
}

View File

@@ -39,10 +39,12 @@ import org.springframework.util.ErrorHandler;
*
* @author Artem Bilan
* @author Gary Russell
* @author Artem Vozhdayenko
*
* @since 5.0
*/
public class AmqpMessageChannelSpec<S extends AmqpMessageChannelSpec<S>> extends AmqpPollableMessageChannelSpec<S> {
public class AmqpMessageChannelSpec<S extends AmqpMessageChannelSpec<S, T>, T extends AbstractAmqpChannel>
extends AmqpPollableMessageChannelSpec<S, T> {
protected final List<Advice> adviceChain = new LinkedList<>(); // NOSONAR
@@ -215,7 +217,7 @@ public class AmqpMessageChannelSpec<S extends AmqpMessageChannelSpec<S>> extends
}
@Override
protected AbstractAmqpChannel doGet() {
protected T doGet() {
this.amqpChannelFactoryBean.setAdviceChain(this.adviceChain.toArray(new Advice[0]));
return super.doGet();
}

View File

@@ -36,11 +36,12 @@ import org.springframework.util.Assert;
*
* @author Artem Bilan
* @author Gary Russell
* @author Artem Vozhdayenko
*
* @since 5.0
*/
public class AmqpPollableMessageChannelSpec<S extends AmqpPollableMessageChannelSpec<S>>
extends MessageChannelSpec<S, AbstractAmqpChannel> {
public class AmqpPollableMessageChannelSpec<S extends AmqpPollableMessageChannelSpec<S, T>, T extends AbstractAmqpChannel>
extends MessageChannelSpec<S, T> {
protected final AmqpChannelFactoryBean amqpChannelFactoryBean; // NOSONAR final
@@ -206,10 +207,11 @@ public class AmqpPollableMessageChannelSpec<S extends AmqpPollableMessageChannel
}
@Override
protected AbstractAmqpChannel doGet() {
@SuppressWarnings("unchecked")
protected T doGet() {
Assert.notNull(getId(), "The 'id' or 'queueName' must be specified");
try {
this.channel = this.amqpChannelFactoryBean.getObject();
this.channel = (T) this.amqpChannelFactoryBean.getObject();
}
catch (Exception e) {
throw new BeanCreationException("Cannot create the AMQP MessageChannel", e);

View File

@@ -18,16 +18,19 @@ package org.springframework.integration.amqp.dsl;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.integration.amqp.channel.PollableAmqpChannel;
/**
* A {@link AmqpMessageChannelSpec} for
* {@link org.springframework.integration.amqp.channel.PublishSubscribeAmqpChannel}s.
*
* @author Artem Bilan
* @author Artem Vozhdayenko
*
* @since 5.0
*/
public class AmqpPublishSubscribeMessageChannelSpec
extends AmqpMessageChannelSpec<AmqpPublishSubscribeMessageChannelSpec> {
extends AmqpMessageChannelSpec<AmqpPublishSubscribeMessageChannelSpec, PollableAmqpChannel> {
protected AmqpPublishSubscribeMessageChannelSpec(ConnectionFactory connectionFactory) {
super(connectionFactory);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2020 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.
@@ -19,6 +19,7 @@ package org.springframework.integration.jms.dsl;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import org.springframework.integration.jms.PollableJmsChannel;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.AbstractMessageListenerContainer;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
@@ -29,6 +30,7 @@ import org.springframework.lang.Nullable;
*
* @author Artem Bilan
* @author Gary Russell
* @author Artem Vozhdayenko
*
* @since 5.0
*/
@@ -39,7 +41,7 @@ public final class Jms {
* @param connectionFactory the JMS ConnectionFactory to build on
* @return the {@link JmsPollableMessageChannelSpec} instance
*/
public static JmsPollableMessageChannelSpec<?> pollableChannel(ConnectionFactory connectionFactory) {
public static JmsPollableMessageChannelSpec<?, PollableJmsChannel> pollableChannel(ConnectionFactory connectionFactory) {
return pollableChannel(null, connectionFactory);
}
@@ -49,10 +51,10 @@ public final class Jms {
* @param connectionFactory the JMS ConnectionFactory to build on
* @return the {@link JmsPollableMessageChannelSpec} instance
*/
public static JmsPollableMessageChannelSpec<?> pollableChannel(@Nullable String id,
public static JmsPollableMessageChannelSpec<?, PollableJmsChannel> pollableChannel(@Nullable String id,
ConnectionFactory connectionFactory) {
return new JmsPollableMessageChannelSpec<>(connectionFactory).id(id);
JmsPollableMessageChannelSpec<?, PollableJmsChannel> spec = new JmsPollableMessageChannelSpec<>(connectionFactory);
return spec.id(id);
}
/**
@@ -60,7 +62,7 @@ public final class Jms {
* @param connectionFactory the JMS ConnectionFactory to build on
* @return the {@link JmsMessageChannelSpec} instance
*/
public static JmsMessageChannelSpec<?> channel(ConnectionFactory connectionFactory) {
public static JmsMessageChannelSpec<?, ?> channel(ConnectionFactory connectionFactory) {
return channel(null, connectionFactory);
}
@@ -70,7 +72,7 @@ public final class Jms {
* @param connectionFactory the JMS ConnectionFactory to build on
* @return the {@link JmsMessageChannelSpec} instance
*/
public static JmsMessageChannelSpec<?> channel(@Nullable String id, ConnectionFactory connectionFactory) {
public static JmsMessageChannelSpec<?, ?> channel(@Nullable String id, ConnectionFactory connectionFactory) {
return new JmsMessageChannelSpec<>(connectionFactory)
.id(id);
}
@@ -180,7 +182,7 @@ public final class Jms {
* @param <C> the {@link AbstractMessageListenerContainer} inheritor type
* @return the {@link JmsInboundGatewaySpec} instance
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({"rawtypes", "unchecked"})
public static <C extends AbstractMessageListenerContainer>
JmsInboundGatewaySpec.JmsInboundGatewayListenerContainerSpec<?, C> inboundGateway(
ConnectionFactory connectionFactory, Class<C> containerClass) {
@@ -241,7 +243,7 @@ public final class Jms {
* @param <C> the {@link AbstractMessageListenerContainer} inheritor type
* @return the {@link JmsMessageDrivenChannelAdapterSpec} instance
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({"rawtypes", "unchecked"})
public static <C extends AbstractMessageListenerContainer>
JmsMessageDrivenChannelAdapterSpec.JmsMessageDrivenChannelAdapterListenerContainerSpec<?, C>
messageDrivenChannelAdapter(ConnectionFactory connectionFactory, Class<C> containerClass) {

View File

@@ -20,6 +20,7 @@ import java.util.concurrent.Executor;
import javax.jms.ConnectionFactory;
import org.springframework.integration.jms.AbstractJmsChannel;
import org.springframework.integration.jms.config.JmsChannelFactoryBean;
import org.springframework.jms.listener.AbstractMessageListenerContainer;
import org.springframework.transaction.PlatformTransactionManager;
@@ -33,9 +34,12 @@ import org.springframework.util.ErrorHandler;
*
* @author Artem Bilan
* @author Gary Russell
* @author Artem Vozhdayenko
*
* @since 5.0
*/
public class JmsMessageChannelSpec<S extends JmsMessageChannelSpec<S>> extends JmsPollableMessageChannelSpec<S> {
public class JmsMessageChannelSpec<S extends JmsMessageChannelSpec<S, T>, T
extends AbstractJmsChannel> extends JmsPollableMessageChannelSpec<S, T> {
protected JmsMessageChannelSpec(ConnectionFactory connectionFactory) {
super(new JmsChannelFactoryBean(true), connectionFactory);

View File

@@ -35,11 +35,12 @@ import org.springframework.lang.Nullable;
*
* @author Artem Bilan
* @author Gary Russell
* @author Artem Vozhdayenko
*
* @since 5.0
*/
public class JmsPollableMessageChannelSpec<S extends JmsPollableMessageChannelSpec<S>>
extends MessageChannelSpec<S, AbstractJmsChannel> {
public class JmsPollableMessageChannelSpec<S extends JmsPollableMessageChannelSpec<S, T>, T extends AbstractJmsChannel>
extends MessageChannelSpec<S, T> {
protected final JmsChannelFactoryBean jmsChannelFactoryBean; // NOSONAR - final
@@ -218,9 +219,10 @@ public class JmsPollableMessageChannelSpec<S extends JmsPollableMessageChannelSp
}
@Override
protected AbstractJmsChannel doGet() {
@SuppressWarnings("unchecked")
protected T doGet() {
try {
this.channel = this.jmsChannelFactoryBean.getObject();
this.channel = (T) this.jmsChannelFactoryBean.getObject();
}
catch (Exception e) {
throw new BeanCreationException("Cannot create the JMS MessageChannel", e);

View File

@@ -18,15 +18,19 @@ package org.springframework.integration.jms.dsl;
import javax.jms.ConnectionFactory;
import org.springframework.integration.jms.SubscribableJmsChannel;
/**
* A {@link JmsMessageChannelSpec} for a {@link org.springframework.integration.jms.SubscribableJmsChannel}
* configured with a topic.
*
* @author Artem Bilan
* @author Artem Vozhdayenko
*
* @since 5.0
*/
public class JmsPublishSubscribeMessageChannelSpec
extends JmsMessageChannelSpec<JmsPublishSubscribeMessageChannelSpec> {
extends JmsMessageChannelSpec<JmsPublishSubscribeMessageChannelSpec, SubscribableJmsChannel> {
protected JmsPublishSubscribeMessageChannelSpec(ConnectionFactory connectionFactory) {
super(connectionFactory);

View File

@@ -83,6 +83,7 @@ import org.springframework.transaction.PlatformTransactionManager;
* @author Artem Bilan
* @author Gary Russell
* @author Nasko Vasilev
* @author Artem Vozhdayenko
*
* @since 5.0
*/
@@ -371,8 +372,7 @@ public class JmsTests extends ActiveMQMultiContextTests {
@Bean
public BroadcastCapableChannel jmsPublishSubscribeChannel() {
// TODO reconsider target generic type for channel implementation to return from this kind of specs
return (BroadcastCapableChannel) Jms.publishSubscribeChannel(jmsConnectionFactory())
return Jms.publishSubscribeChannel(jmsConnectionFactory())
.destination("pubsub")
.get();
}