From f18a58662d7d299e57a1d4e97d434427745124cc Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 2 Jul 2021 14:59:40 -0400 Subject: [PATCH] Functional gateway bean definitions * Rework `MessagingGatewayRegistrar` to parse messaging gateway annotation an `` XML using a supplier variant for bean definition. Such a feature is required by Spring Native - otherwise we would need to register reflection info for to many internal Spring Integration classes * Such a change should benefit from regular JDK perspective, too - we don't do reflection for this kind of bean registrations --- .../config/MessagingGatewayRegistrar.java | 202 ++++++++++++------ .../integration/config/xml/GatewayParser.java | 124 +++++++---- .../config/xml/GatewayParserTests.java | 4 +- 3 files changed, 219 insertions(+), 111 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java index da9019fbe87..e3ec9f9064c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 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. @@ -18,30 +18,39 @@ import java.beans.Introspector; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.stream.Collectors; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.config.EmbeddedValueResolver; import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.annotation.AnnotationConstants; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.gateway.GatewayMethodMetadata; import org.springframework.integration.gateway.GatewayProxyFactoryBean; +import org.springframework.integration.gateway.MethodArgsMessageMapper; import org.springframework.integration.util.MessagingAnnotationUtils; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -58,6 +67,8 @@ */ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar { + private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); + private static final String PROXY_DEFAULT_METHODS_ATTR = "proxyDefaultMethods"; @Override @@ -72,11 +83,14 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B annotationAttributes.put("serviceInterface", importingClassMetadata.getClassName()); annotationAttributes.put(PROXY_DEFAULT_METHODS_ATTR, "" + annotationAttributes.remove(PROXY_DEFAULT_METHODS_ATTR)); - BeanDefinitionReaderUtils.registerBeanDefinition(parse(annotationAttributes), registry); + BeanDefinitionReaderUtils.registerBeanDefinition(gatewayProxyBeanDefinition(annotationAttributes, registry), + registry); } } - public BeanDefinitionHolder parse(Map gatewayAttributes) { // NOSONAR complexity + public BeanDefinitionHolder gatewayProxyBeanDefinition(Map gatewayAttributes, + BeanDefinitionRegistry registry) { + String defaultPayloadExpression = (String) gatewayAttributes.get("defaultPayloadExpression"); @SuppressWarnings("unchecked") @@ -98,89 +112,143 @@ public BeanDefinitionHolder parse(Map gatewayAttributes) { // NO Assert.state(!hasMapper || !hasDefaultHeaders, "'defaultHeaders' are not allowed when a 'mapper' is provided"); - BeanDefinitionBuilder gatewayProxyBuilder = - BeanDefinitionBuilder.genericBeanDefinition(GatewayProxyFactoryBean.class); - - if (hasDefaultHeaders || hasDefaultPayloadExpression) { - BeanDefinitionBuilder methodMetadataBuilder = - BeanDefinitionBuilder.genericBeanDefinition(GatewayMethodMetadata.class); + ConfigurableBeanFactory beanFactory = obtainBeanFactory(registry); + EmbeddedValueResolver embeddedValueResolver = new EmbeddedValueResolver(beanFactory); + Class serviceInterface = getServiceInterface((String) gatewayAttributes.get("serviceInterface"), beanFactory); - if (hasDefaultPayloadExpression) { - methodMetadataBuilder.addPropertyValue("payloadExpression", - BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class) - .addConstructorArgValue(defaultPayloadExpression) - .getBeanDefinition()); - } + @SuppressWarnings("unchecked") + AbstractBeanDefinition beanDefinition = new RootBeanDefinition(GatewayProxyFactoryBean.class, + () -> { + GatewayProxyFactoryBean proxyFactoryBean = new GatewayProxyFactoryBean(serviceInterface); + if (StringUtils.hasText(defaultRequestChannel)) { + proxyFactoryBean.setDefaultRequestChannelName(defaultRequestChannel); + } + if (StringUtils.hasText(defaultReplyChannel)) { + proxyFactoryBean.setDefaultReplyChannelName(defaultReplyChannel); + } + if (StringUtils.hasText(errorChannel)) { + proxyFactoryBean.setErrorChannelName(errorChannel); + } + if (StringUtils.hasText(proxyDefaultMethods)) { + boolean actualProxyDefaultMethods = + Boolean.parseBoolean(embeddedValueResolver.resolveStringValue(proxyDefaultMethods)); + proxyFactoryBean.setProxyDefaultMethods(actualProxyDefaultMethods); + } + if (StringUtils.hasText(mapper)) { + proxyFactoryBean.setMapper(beanFactory.getBean(mapper, MethodArgsMessageMapper.class)); + } - if (hasDefaultHeaders) { - Map headerExpressions = new ManagedMap<>(); - for (Map header : defaultHeaders) { - String headerValue = (String) header.get("value"); - String headerExpression = (String) header.get("expression"); - boolean hasValue = StringUtils.hasText(headerValue); + if (asyncExecutor == null || AnnotationConstants.NULL.equals(asyncExecutor)) { + proxyFactoryBean.setAsyncExecutor(null); + } + else if (StringUtils.hasText(asyncExecutor)) { + proxyFactoryBean.setAsyncExecutor(beanFactory.getBean(asyncExecutor, Executor.class)); + } - if (hasValue == StringUtils.hasText(headerExpression)) { - throw new BeanDefinitionStoreException("exactly one of 'value' or 'expression' " + - "is required on a gateway's header."); + if (hasDefaultHeaders || hasDefaultPayloadExpression) { + GatewayMethodMetadata globalMethodMetadata = + createGlobalMethodMetadata(defaultPayloadExpression, defaultHeaders, + hasDefaultPayloadExpression, hasDefaultHeaders, embeddedValueResolver); + proxyFactoryBean.setGlobalMethodMetadata(globalMethodMetadata); } - BeanDefinition expressionDef = - new RootBeanDefinition(hasValue ? LiteralExpression.class : ExpressionFactoryBean.class); - expressionDef.getConstructorArgumentValues() - .addGenericArgumentValue(hasValue ? headerValue : headerExpression); + Map methodDefinitions = + (Map) gatewayAttributes.get("methods"); - headerExpressions.put((String) header.get("name"), expressionDef); - } - methodMetadataBuilder.addPropertyValue("headerExpressions", headerExpressions); - } + if (methodDefinitions != null) { + Map methodMetadataMap = + methodDefinitions.entrySet() + .stream() + .collect(Collectors.toMap(Entry::getKey, + entry -> (GatewayMethodMetadata) entry.getValue().getInstanceSupplier().get())); - gatewayProxyBuilder.addPropertyValue("globalMethodMetadata", methodMetadataBuilder.getBeanDefinition()); - } + proxyFactoryBean.setMethodMetadataMap(methodMetadataMap); + } + String actualDefaultRequestTimeout = + embeddedValueResolver.resolveStringValue( + (String) gatewayAttributes.get("defaultRequestTimeout")); + if (actualDefaultRequestTimeout != null) { + proxyFactoryBean.setDefaultRequestTimeoutExpressionString(actualDefaultRequestTimeout); + } + String actualDefaultReplyTimeout = + embeddedValueResolver.resolveStringValue( + (String) gatewayAttributes.get("defaultReplyTimeout")); + if (actualDefaultReplyTimeout != null) { + proxyFactoryBean.setDefaultReplyTimeoutExpressionString(actualDefaultReplyTimeout); + } + return proxyFactoryBean; + }); - if (StringUtils.hasText(defaultRequestChannel)) { - gatewayProxyBuilder.addPropertyValue("defaultRequestChannelName", defaultRequestChannel); - } - if (StringUtils.hasText(defaultReplyChannel)) { - gatewayProxyBuilder.addPropertyValue("defaultReplyChannelName", defaultReplyChannel); + String id = (String) gatewayAttributes.get("name"); + if (!StringUtils.hasText(id)) { + String serviceInterfaceName = serviceInterface.getName(); + id = Introspector.decapitalize(serviceInterfaceName.substring(serviceInterfaceName.lastIndexOf('.') + 1)); } - if (StringUtils.hasText(errorChannel)) { - gatewayProxyBuilder.addPropertyValue("errorChannelName", errorChannel); + + beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, serviceInterface); + return new BeanDefinitionHolder(beanDefinition, id); + } + + private static ConfigurableBeanFactory obtainBeanFactory(BeanDefinitionRegistry registry) { + if (registry instanceof ConfigurableBeanFactory) { + return (ConfigurableBeanFactory) registry; } - if (asyncExecutor == null || AnnotationConstants.NULL.equals(asyncExecutor)) { - gatewayProxyBuilder.addPropertyValue("asyncExecutor", null); + else if (registry instanceof ConfigurableApplicationContext) { + return ((ConfigurableApplicationContext) registry).getBeanFactory(); } - else if (StringUtils.hasText(asyncExecutor)) { - gatewayProxyBuilder.addPropertyReference("asyncExecutor", asyncExecutor); + throw new IllegalArgumentException("The provided 'BeanDefinitionRegistry' must be an instance " + + "of 'ConfigurableBeanFactory' or 'ConfigurableApplicationContext', but given is: " + + registry.getClass()); + } + + private static Class getServiceInterface(String serviceInterface, ConfigurableBeanFactory beanFactory) { + String actualServiceInterface = beanFactory.resolveEmbeddedValue(serviceInterface); + if (!StringUtils.hasText(actualServiceInterface)) { + return org.springframework.integration.gateway.RequestReplyExchanger.class; } - if (StringUtils.hasText(mapper)) { - gatewayProxyBuilder.addPropertyReference("mapper", mapper); + try { + return ClassUtils.forName(actualServiceInterface, beanFactory.getBeanClassLoader()); } - if (StringUtils.hasText(proxyDefaultMethods)) { - gatewayProxyBuilder.addPropertyValue(PROXY_DEFAULT_METHODS_ATTR, proxyDefaultMethods); + catch (ClassNotFoundException ex) { + throw new BeanDefinitionStoreException("Cannot parse class for service interface", ex); } + } - gatewayProxyBuilder.addPropertyValue("defaultRequestTimeoutExpressionString", - gatewayAttributes.get("defaultRequestTimeout")); - gatewayProxyBuilder.addPropertyValue("defaultReplyTimeoutExpressionString", - gatewayAttributes.get("defaultReplyTimeout")); - gatewayProxyBuilder.addPropertyValue("methodMetadataMap", gatewayAttributes.get("methods")); + private static GatewayMethodMetadata createGlobalMethodMetadata(String defaultPayloadExpression, + Map[] defaultHeaders, boolean hasDefaultPayloadExpression, + boolean hasDefaultHeaders, EmbeddedValueResolver embeddedValueResolver) { + GatewayMethodMetadata gatewayMethodMetadata = new GatewayMethodMetadata(); - String serviceInterface = (String) gatewayAttributes.get("serviceInterface"); - if (!StringUtils.hasText(serviceInterface)) { - serviceInterface = "org.springframework.integration.gateway.RequestReplyExchanger"; - } - String id = (String) gatewayAttributes.get("name"); - if (!StringUtils.hasText(id)) { - id = Introspector.decapitalize(serviceInterface.substring(serviceInterface.lastIndexOf('.') + 1)); + if (hasDefaultPayloadExpression) { + String actualPayloadExpression = embeddedValueResolver.resolveStringValue(defaultPayloadExpression); + gatewayMethodMetadata.setPayloadExpression(EXPRESSION_PARSER.parseExpression(actualPayloadExpression)); } - gatewayProxyBuilder.addConstructorArgValue(serviceInterface); + if (hasDefaultHeaders) { + Map headerExpressions = new HashMap<>(); + for (Map header : defaultHeaders) { + String headerValue = (String) header.get("value"); + String headerExpression = (String) header.get("expression"); + boolean hasValue = StringUtils.hasText(headerValue); - AbstractBeanDefinition beanDefinition = gatewayProxyBuilder.getBeanDefinition(); - beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, serviceInterface); - return new BeanDefinitionHolder(beanDefinition, id); + if (hasValue == StringUtils.hasText(headerExpression)) { + throw new BeanDefinitionStoreException("exactly one of 'value' or 'expression' " + + "is required on a gateway's header."); + } + + Expression expression = + hasValue + ? new LiteralExpression(embeddedValueResolver.resolveStringValue(headerValue)) + : EXPRESSION_PARSER.parseExpression( + embeddedValueResolver.resolveStringValue(headerExpression)); + + headerExpressions.put((String) header.get("name"), expression); + } + gatewayMethodMetadata.setHeaderExpressions(headerExpressions); + } + return gatewayMethodMetadata; } /** diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java index cf468a0e047..e8124566b3f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 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. @@ -25,13 +25,20 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.config.EmbeddedValueResolver; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.integration.config.ExpressionFactoryBean; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.config.MessagingGatewayRegistrar; import org.springframework.integration.gateway.GatewayMethodMetadata; import org.springframework.util.Assert; @@ -49,6 +56,8 @@ */ public class GatewayParser implements BeanDefinitionParser { + private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); + private final MessagingGatewayRegistrar registrar = new MessagingGatewayRegistrar(); @Override @@ -88,7 +97,8 @@ public BeanDefinition parse(final Element element, ParserContext parserContext) gatewayAttributes.put("proxyDefaultMethods", element.getAttribute("proxy-default-methods")); - BeanDefinitionHolder gatewayHolder = this.registrar.parse(gatewayAttributes); + BeanDefinitionHolder gatewayHolder = + this.registrar.gatewayProxyBeanDefinition(gatewayAttributes, parserContext.getRegistry()); if (isNested) { return gatewayHolder.getBeanDefinition(); } @@ -116,51 +126,81 @@ private void headers(Element element, Map gatewayAttributes) { private void methods(final Element element, ParserContext parserContext, final Map gatewayAttributes) { + List methodElements = DomUtils.getChildElementsByTagName(element, "method"); if (!CollectionUtils.isEmpty(methodElements)) { - Map methodMetadataMap = new ManagedMap<>(); + + ConfigurableBeanFactory beanFactory = obtainBeanFactory(parserContext.getRegistry()); + Map methodMetadataMap = new HashMap<>(); for (Element methodElement : methodElements) { String methodName = methodElement.getAttribute(AbstractBeanDefinitionParser.NAME_ATTRIBUTE); - BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition( - GatewayMethodMetadata.class); - methodMetadataBuilder.addPropertyValue("requestChannelName", - methodElement.getAttribute("request-channel")); - methodMetadataBuilder.addPropertyValue("replyChannelName", methodElement.getAttribute("reply-channel")); - methodMetadataBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout")); - methodMetadataBuilder.addPropertyValue("replyTimeout", methodElement.getAttribute("reply-timeout")); - - boolean hasMapper = StringUtils.hasText(element.getAttribute("mapper")); - String payloadExpression = methodElement.getAttribute("payload-expression"); - Assert.state(!hasMapper || !StringUtils.hasText(payloadExpression), - "'payload-expression' is not allowed when a 'mapper' is provided"); - - if (StringUtils.hasText(payloadExpression)) { - methodMetadataBuilder.addPropertyValue("payloadExpression", - BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class) - .addConstructorArgValue(payloadExpression) - .getBeanDefinition()); - } - - List invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header"); - if (!CollectionUtils.isEmpty(invocationHeaders)) { - Assert.state(!hasMapper, "header elements are not allowed when a 'mapper' is provided"); - - Map headerExpressions = new ManagedMap<>(); - for (Element headerElement : invocationHeaders) { - BeanDefinition expressionDef = IntegrationNamespaceUtils - .createExpressionDefinitionFromValueOrExpression("value", "expression", parserContext, - headerElement, true); - - headerExpressions.put(headerElement.getAttribute(AbstractBeanDefinitionParser.NAME_ATTRIBUTE), - expressionDef); - } - methodMetadataBuilder.addPropertyValue("headerExpressions", headerExpressions); - } - methodMetadataMap.put(methodName, methodMetadataBuilder.getBeanDefinition()); + + AbstractBeanDefinition gatewayMethodMetadataBd = + new RootBeanDefinition(GatewayMethodMetadata.class, + () -> createGatewayMethodMetadata(element, beanFactory, methodElement)); + + methodMetadataMap.put(methodName, gatewayMethodMetadataBd); } gatewayAttributes.put("methods", methodMetadataMap); } } + private static ConfigurableBeanFactory obtainBeanFactory(BeanDefinitionRegistry registry) { + if (registry instanceof ConfigurableBeanFactory) { + return (ConfigurableBeanFactory) registry; + } + else if (registry instanceof ConfigurableApplicationContext) { + return ((ConfigurableApplicationContext) registry).getBeanFactory(); + } + throw new IllegalArgumentException("The provided 'BeanDefinitionRegistry' must be an instance " + + "of 'ConfigurableBeanFactory' or 'ConfigurableApplicationContext', but given is: " + + registry.getClass()); + } + + private GatewayMethodMetadata createGatewayMethodMetadata(Element element, + ConfigurableBeanFactory beanFactory, Element methodElement) { + + EmbeddedValueResolver embeddedValueResolver = new EmbeddedValueResolver(beanFactory); + GatewayMethodMetadata gatewayMethodMetadata = new GatewayMethodMetadata(); + gatewayMethodMetadata.setRequestChannelName(methodElement.getAttribute("request-channel")); + gatewayMethodMetadata.setReplyChannelName(methodElement.getAttribute("reply-channel")); + gatewayMethodMetadata.setRequestTimeout( + embeddedValueResolver.resolveStringValue(methodElement.getAttribute("request-timeout"))); + gatewayMethodMetadata.setReplyTimeout( + embeddedValueResolver.resolveStringValue(methodElement.getAttribute("reply-timeout"))); + + boolean hasMapper = StringUtils.hasText(element.getAttribute("mapper")); + String payloadExpression = methodElement.getAttribute("payload-expression"); + Assert.state(!hasMapper || !StringUtils.hasText(payloadExpression), + "'payload-expression' is not allowed when a 'mapper' is provided"); + + if (StringUtils.hasText(payloadExpression)) { + gatewayMethodMetadata.setPayloadExpression( + EXPRESSION_PARSER.parseExpression(embeddedValueResolver.resolveStringValue(payloadExpression))); + } + + List invocationHeaders = DomUtils.getChildElementsByTagName(methodElement, "header"); + if (!CollectionUtils.isEmpty(invocationHeaders)) { + Assert.state(!hasMapper, "header elements are not allowed when a 'mapper' is provided"); + + Map headerExpressions = new HashMap<>(); + for (Element headerElement : invocationHeaders) { + String headerValue = headerElement.getAttribute("value"); + String headerExpression = headerElement.getAttribute("expression"); + Expression expression = + StringUtils.hasText(headerValue) + ? new LiteralExpression(embeddedValueResolver.resolveStringValue(headerValue)) + : EXPRESSION_PARSER.parseExpression( + embeddedValueResolver.resolveStringValue(headerExpression)); + + headerExpressions.put(headerElement.getAttribute(AbstractBeanDefinitionParser.NAME_ATTRIBUTE), + expression); + } + gatewayMethodMetadata.setHeaderExpressions(headerExpressions); + } + return gatewayMethodMetadata; + } + + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java index 09317baef04..43e2b2ae1dc 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java @@ -181,7 +181,7 @@ public void testFactoryBeanObjectTypeWithServiceInterface() { ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext) context).getBeanFactory(); Object attribute = beanFactory.getMergedBeanDefinition("&oneWay").getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE); - assertThat(attribute).isEqualTo(TestService.class.getName()); + assertThat(attribute).isEqualTo(TestService.class); } @Test @@ -189,7 +189,7 @@ public void testFactoryBeanObjectTypeWithNoServiceInterface() { ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext) context).getBeanFactory(); Object attribute = beanFactory.getMergedBeanDefinition("&defaultConfig").getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE); - assertThat(attribute).isEqualTo(RequestReplyExchanger.class.getName()); + assertThat(attribute).isEqualTo(RequestReplyExchanger.class); } @Test