Add SpringExtensions abstract utility class extending the functionality of core Spring.

This commit is contained in:
John Blum
2021-08-18 14:44:21 -07:00
parent 389feac355
commit 78d0f14349
2 changed files with 307 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
/*
* Copyright 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.
* You may obtain a copy of the License at
*
* https://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.geode.core.util;
import java.util.Optional;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
* {@link SpringExtensions} is an abstract utility class containing functions to extend the functionality of Spring.
*
* @author John Blum
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.config.BeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.context.ApplicationContext
* @since 1.6.0
*/
@SuppressWarnings("unused")
public abstract class SpringExtensions {
public static final String BEAN_DEFINITION_METADATA_JSON = "{\n"
+ "\t'beanName': '%1$s',%n"
+ "\t'beanClassName': '%2$s',%n"
+ "\t'description': '%3$s',%n"
+ "\t'originatingBeanDefinition': '%4$s',%n"
+ "\t'parentName': '%5$s',%n"
+ "\t'resourceDescription': '%6$s',%n"
+ "\t'source': '%7$s',%n"
+ "}";
public static final String EMPTY_JSON_OBJECT = "{}";
public static @NonNull String getBeanDefinitionMetadata(@NonNull String beanName,
@Nullable ApplicationContext applicationContext) {
return Optional.ofNullable(applicationContext)
.filter(ConfigurableApplicationContext.class::isInstance)
.map(ConfigurableApplicationContext.class::cast)
.map(ConfigurableApplicationContext::getBeanFactory)
.map(beanFactory -> getBeanDefinitionMetadata(beanName, beanFactory))
.orElse(EMPTY_JSON_OBJECT);
}
public static @NonNull String getBeanDefinitionMetadata(@NonNull String beanName,
@Nullable BeanFactory beanFactory) {
return Optional.ofNullable(beanFactory)
.filter(BeanDefinitionRegistry.class::isInstance)
.map(BeanDefinitionRegistry.class::cast)
.map(registry -> getBeanDefinitionMetadata(beanName, registry))
.orElse(EMPTY_JSON_OBJECT);
}
public static @NonNull String getBeanDefinitionMetadata(@NonNull String beanName,
@Nullable BeanDefinitionRegistry beanDefinitionRegistry) {
return Optional.ofNullable(beanDefinitionRegistry)
.filter(registry -> StringUtils.hasText(beanName))
.map(registry -> registry.getBeanDefinition(beanName))
.map(beanDefinition -> getBeanDefinitionMetadata(beanName, beanDefinition))
.orElse(EMPTY_JSON_OBJECT);
}
public static @NonNull String getBeanDefinitionMetadata(@Nullable String beanName,
@Nullable BeanDefinition beanDefinition) {
if (beanDefinition != null) {
return String.format(BEAN_DEFINITION_METADATA_JSON, beanName,
beanDefinition.getBeanClassName(),
beanDefinition.getDescription(),
beanDefinition.getOriginatingBeanDefinition(),
beanDefinition.getParentName(),
beanDefinition.getResourceDescription(),
beanDefinition.getSource());
}
return EMPTY_JSON_OBJECT;
}
}

View File

@@ -0,0 +1,207 @@
/*
* Copyright 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.
* You may obtain a copy of the License at
*
* https://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.geode.core.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Unit Tests for {@link SpringExtensions}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.geode.core.util.SpringExtensions
* @since 1.0.0
*/
public class SpringExtensionsUnitTests {
private void verifyBeanDefinitionInteractions(BeanDefinition mockBeanDefinition) {
verify(mockBeanDefinition, times(1)).getBeanClassName();
verify(mockBeanDefinition, times(1)).getDescription();
verify(mockBeanDefinition, times(1)).getOriginatingBeanDefinition();
verify(mockBeanDefinition, times(1)).getParentName();
verify(mockBeanDefinition, times(1)).getResourceDescription();
verify(mockBeanDefinition, times(1)).getSource();
verifyNoMoreInteractions(mockBeanDefinition);
}
@Test
public void getBeanDefinitionMetadataFromApplicationContext() {
BeanDefinition mockBeanDefinition = mock(BeanDefinition.class);
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class);
ConfigurableListableBeanFactoryBeanDefinitionRegistry mockBeanDefinitionRegistry =
mock(ConfigurableListableBeanFactoryBeanDefinitionRegistry.class);
String beanName = "TestBeanName";
doReturn(mockBeanDefinitionRegistry).when(mockApplicationContext).getBeanFactory();
doReturn(mockBeanDefinition).when(mockBeanDefinitionRegistry).getBeanDefinition(eq(beanName));
String actualJson = SpringExtensions.getBeanDefinitionMetadata(beanName, mockApplicationContext);
assertThat(actualJson).isNotEmpty();
assertThat(actualJson).contains(beanName);
verifyBeanDefinitionInteractions(mockBeanDefinition);
}
@Test
public void getBeanDefinitionMetadataFromNullApplicationContextReturnsEmptyJsonObject() {
assertThat(SpringExtensions.getBeanDefinitionMetadata("TestBeanName", (ApplicationContext) null))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
}
@Test
public void getBeanDefinitionMetadataFromNonConfigurableApplicationContextReturnsEmptyJsonObject() {
ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
assertThat(SpringExtensions.getBeanDefinitionMetadata("TestBeanName", mockApplicationContext))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
verifyNoInteractions(mockApplicationContext);
}
@Test
public void getBeanDefinitionMetadataFromApplicationContextWithNullBeanFactoryReturnsEmptyJsonObject() {
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class);
doReturn(null).when(mockApplicationContext).getBeanFactory();
assertThat(SpringExtensions.getBeanDefinitionMetadata("TestBeanName", mockApplicationContext))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
verify(mockApplicationContext, times(1)).getBeanFactory();
verifyNoMoreInteractions(mockApplicationContext);
}
@Test
public void getBeanDefinitionMetadataFromNullBeanFactoryReturnsEmptyJsonObject() {
assertThat(SpringExtensions.getBeanDefinitionMetadata("TestBeanName", (BeanFactory) null))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
}
@Test
public void getBeanDefinitionMetadataFromNullBeanDefinitionRegistryReturnsEmptyJsonObject() {
assertThat(SpringExtensions.getBeanDefinitionMetadata("TestBeanName", (BeanDefinitionRegistry) null))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
}
private void testGetBeanDefinitionMetadataFromInvalidBeanNameReturnsEmptyJsonObject(String beanName) {
BeanDefinitionRegistry mockBeanDefinitionRegistry = mock(BeanDefinitionRegistry.class);
assertThat(SpringExtensions.getBeanDefinitionMetadata(beanName, mockBeanDefinitionRegistry))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
verifyNoInteractions(mockBeanDefinitionRegistry);
}
@Test
public void getBeanDefinitionMetadataFromBlankBeanNameReturnsEmptyJsonObject() {
testGetBeanDefinitionMetadataFromInvalidBeanNameReturnsEmptyJsonObject(" ");
}
@Test
public void getBeanDefinitionMetadataFromEmptyBeanNameReturnsEmptyJsonObject() {
testGetBeanDefinitionMetadataFromInvalidBeanNameReturnsEmptyJsonObject("");
}
@Test
public void getBeanDefinitionMetadataFromNullBeanNameReturnsEmptyJsonObject() {
testGetBeanDefinitionMetadataFromInvalidBeanNameReturnsEmptyJsonObject(null);
}
@Test
public void getBeanDefinitionMetadataFromBeanDefinitionRegistryReturningNullBeanDefinitionReturnsEmptyJsonObject() {
BeanDefinitionRegistry mockBeanDefinitionRegistry = mock(BeanDefinitionRegistry.class);
doReturn(null).when(mockBeanDefinitionRegistry).getBeanDefinition(any());
assertThat(SpringExtensions.getBeanDefinitionMetadata("TestBeanName", mockBeanDefinitionRegistry))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
verify(mockBeanDefinitionRegistry, times(1)).getBeanDefinition(eq("TestBeanName"));
verifyNoMoreInteractions(mockBeanDefinitionRegistry);
}
@Test
public void getBeanDefinitionMetadataForBeanDefinitionReturnsJson() {
BeanDefinition mockBeanDefinition = mock(BeanDefinition.class);
BeanDefinition mockOriginatingBeanDefinition = mock(BeanDefinition.class);
Object testSource = new Object();
doReturn("test.bean.ClassName").when(mockBeanDefinition).getBeanClassName();
doReturn("TestDescription").when(mockBeanDefinition).getDescription();
doReturn(mockOriginatingBeanDefinition).when(mockBeanDefinition).getOriginatingBeanDefinition();
doReturn("TestParentName").when(mockBeanDefinition).getParentName();
doReturn("TestResourceDescription").when(mockBeanDefinition).getResourceDescription();
doReturn(testSource).when(mockBeanDefinition).getSource();
String expectedJson = String.format(SpringExtensions.BEAN_DEFINITION_METADATA_JSON,
"TestBeanName", "test.bean.ClassName", "TestDescription", mockOriginatingBeanDefinition, "TestParentName",
"TestResourceDescription", testSource);
String actualJson = SpringExtensions.getBeanDefinitionMetadata("TestBeanName", mockBeanDefinition);
assertThat(actualJson).isEqualTo(expectedJson);
verifyBeanDefinitionInteractions(mockBeanDefinition);
verifyNoInteractions(mockOriginatingBeanDefinition);
}
@Test
public void getBeanDefinitionMetadataForNullBeanDefinitionReturnsEmptyJsonObject() {
assertThat(SpringExtensions.getBeanDefinitionMetadata("TestBeanName", (BeanDefinition) null))
.isEqualTo(SpringExtensions.EMPTY_JSON_OBJECT);
}
private interface ConfigurableListableBeanFactoryBeanDefinitionRegistry
extends BeanDefinitionRegistry, ConfigurableListableBeanFactory { }
}