JAVA-19964 Move code from spring-core-5 to spring-core-2 (#13856)

* JAVA-19964 Move code from spring-core-5 to spring-core-2

* JAVA-19964 Move code from spring-core-6 to spring-core-2

* JAVA-19964 Move code from spring-core-4 to spring-core-3
This commit is contained in:
anuragkumawat
2023-04-22 13:23:07 +05:30
committed by GitHub
parent b0116c225e
commit a5fa999031
51 changed files with 75 additions and 261 deletions
@@ -0,0 +1,20 @@
package com.baeldung.applicationcontext;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextProvider.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
@@ -0,0 +1,11 @@
package com.baeldung.applicationcontext;
import org.springframework.stereotype.Service;
@Service
public class ItemService {
public String getItem(){
return "New Item";
}
}
@@ -0,0 +1,17 @@
package com.baeldung.applicationcontext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
@Autowired
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
}
@@ -0,0 +1,12 @@
package com.baeldung.component.autoproxying;
import lombok.Getter;
import org.springframework.stereotype.Component;
@Getter
@Component
public class DataCache {
@RandomInt(min = 2, max = 10)
private int group;
private String name;
}
@@ -0,0 +1,33 @@
package com.baeldung.component.autoproxying;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
public class EligibleForAutoProxyRandomIntProcessor implements BeanPostProcessor {
private final RandomIntGenerator randomIntGenerator;
@Lazy
public EligibleForAutoProxyRandomIntProcessor(RandomIntGenerator randomIntGenerator) {
this.randomIntGenerator = randomIntGenerator;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
RandomInt injectRandomInt = field.getAnnotation(RandomInt.class);
if (injectRandomInt != null) {
int min = injectRandomInt.min();
int max = injectRandomInt.max();
int randomValue = randomIntGenerator.generate(min, max);
field.setAccessible(true);
ReflectionUtils.setField(field, bean, randomValue);
}
}
return bean;
}
}
@@ -0,0 +1,31 @@
package com.baeldung.component.autoproxying;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
public class NotEligibleForAutoProxyRandomIntProcessor implements BeanPostProcessor {
private final RandomIntGenerator randomIntGenerator;
public NotEligibleForAutoProxyRandomIntProcessor(RandomIntGenerator randomIntGenerator) {
this.randomIntGenerator = randomIntGenerator;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
RandomInt injectRandomInt = field.getAnnotation(RandomInt.class);
if (injectRandomInt != null) {
int min = injectRandomInt.min();
int max = injectRandomInt.max();
int randomValue = randomIntGenerator.generate(min, max);
field.setAccessible(true);
ReflectionUtils.setField(field, bean, randomValue);
}
}
return bean;
}
}
@@ -0,0 +1,11 @@
package com.baeldung.component.autoproxying;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface RandomInt {
int min();
int max();
}
@@ -0,0 +1,21 @@
package com.baeldung.component.autoproxying;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Random;
@Slf4j
@Component
public class RandomIntGenerator {
private final Random random = new Random();
private final DataCache dataCache;
public RandomIntGenerator(DataCache dataCache) {
this.dataCache = dataCache;
}
public int generate(int min, int max) {
return random.nextInt(max - min) + min;
}
}
@@ -0,0 +1,11 @@
package com.baeldung.concurrentrequest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConcurrentRequestApplication {
public static void main(String[] args) {
SpringApplication.run(ConcurrentRequestApplication.class, args);
}
}
@@ -0,0 +1,26 @@
package com.baeldung.concurrentrequest;
public class Product {
private final int id;
private final String name;
private final Stock stock;
public Product(int id, String name, Stock stock) {
this.id = id;
this.name = name;
this.stock = stock;
}
public Stock getStock() {
return stock;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
@@ -0,0 +1,30 @@
package com.baeldung.concurrentrequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController()
@RequestMapping("product")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping("/{id}")
public Product getProductDetails(@PathVariable("id") int productId) {
return productService.getProductById(productId)
.orElse(null);
}
@GetMapping("{id}/stock")
public Stock getProductStock(@PathVariable("id") int productId) {
return productService.getProductById(productId)
.map(Product::getStock)
.orElse(null);
}
}
@@ -0,0 +1,32 @@
package com.baeldung.concurrentrequest;
import static java.lang.Thread.currentThread;
import static java.util.Arrays.asList;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
// @formatter:off
private final static List<Product> productRepository = asList(
new Product(1, "Product 1", new Stock(100)),
new Product(2, "Product 2", new Stock(50))
);
// @formatter:on
public Optional<Product> getProductById(int id) {
Optional<Product> product = productRepository.stream()
.filter(p -> p.getId() == id)
.findFirst();
String productName = product.map(Product::getName)
.orElse(null);
System.out.printf("Thread: %s; bean instance: %s; product id: %s has the name: %s%n", currentThread().getName(), this, id, productName);
return product;
}
}
@@ -0,0 +1,13 @@
package com.baeldung.concurrentrequest;
public class Stock {
private final int inStockItems;
public Stock(int inStockItems) {
this.inStockItems = inStockItems;
}
public int getInStockItems() {
return inStockItems;
}
}
@@ -0,0 +1,11 @@
package com.baeldung.reinitializebean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ReinitializeBeanApp {
public static void main(String[] args) {
SpringApplication.run(ReinitializeBeanApp.class, args);
}
}
@@ -0,0 +1,50 @@
package com.baeldung.reinitializebean.cache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@Service("ConfigManager")
public class ConfigManager {
private static final Log LOG = LogFactory.getLog(ConfigManager.class);
private Map<String,Object> config;
private final String filePath;
public ConfigManager(@Value("${config.file.path}") String filePath) {
this.filePath = filePath;
initConfigs();
}
private void initConfigs() {
Properties properties = new Properties();
try {
properties.load(Files.newInputStream(Paths.get(filePath)));
} catch (IOException e) {
LOG.error("Error loading configuration:", e);
}
config = new HashMap<>();
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
config.put(String.valueOf(entry.getKey()), entry.getValue());
}
}
public Object getConfig(String key) {
return config.get(key);
}
public void reinitializeConfig() {
initConfigs();
}
}
@@ -0,0 +1,55 @@
package com.baeldung.reinitializebean.controller;
import com.baeldung.reinitializebean.cache.ConfigManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/config")
public class ConfigController {
@Value("${config.file.path}")
private String filePath;
private final ApplicationContext applicationContext;
private final ConfigManager configManager;
public ConfigController(ApplicationContext applicationContext, ConfigManager configManager) {
this.applicationContext = applicationContext;
this.configManager = configManager;
}
@GetMapping("/reinitializeConfig")
public void reinitializeConfig() {
configManager.reinitializeConfig();
}
@GetMapping("/reinitializeBean")
public void reinitializeBean() {
DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) applicationContext.getAutowireCapableBeanFactory();
registry.destroySingleton("ConfigManager");
registry.registerSingleton("ConfigManager", new ConfigManager(filePath));
}
@GetMapping("/destroyBean")
public void destroyBean() {
DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) applicationContext.getAutowireCapableBeanFactory();
registry.destroySingleton("ConfigManager");
}
@GetMapping("/{key}")
public Object get(@PathVariable String key) {
return configManager.getConfig(key);
}
@GetMapping("/context/{key}")
public Object getFromContext(@PathVariable String key) {
ConfigManager dynamicConfigManager = applicationContext.getBean(ConfigManager.class);
return dynamicConfigManager.getConfig(key);
}
}
@@ -0,0 +1,20 @@
package com.baeldung.version;
import org.springframework.boot.system.JavaVersion;
import org.springframework.boot.system.SystemProperties;
import org.springframework.core.SpringVersion;
public class VersionObtainer {
public String getSpringVersion() {
return SpringVersion.getVersion();
}
public String getJavaVersion() {
return JavaVersion.getJavaVersion().toString();
}
public String getJdkVersion() {
return SystemProperties.get("java.version");
}
}
@@ -0,0 +1 @@
config.file.path=./spring-core-2/src/main/resources/config.properties
@@ -0,0 +1 @@
property1=value2
@@ -0,0 +1,32 @@
package com.baeldung.applicationcontext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ContextConfiguration(classes = TestContextConfig.class)
@ExtendWith(SpringExtension.class)
class ApplicationContextProviderUnitTest {
@Test
void whenGetApplicationContext_thenReturnApplicationContext() {
ApplicationContext context = ApplicationContextProvider.getApplicationContext();
assertNotNull(context);
System.out.printf("ApplicationContext has %d beans %n", context.getBeanDefinitionCount());
}
@Test
void whenGetBean_thenReturnItemServiceReference() {
ApplicationContext context = ApplicationContextProvider.getApplicationContext();
assertNotNull(context);
ItemService itemService = context.getBean(ItemService.class);
assertNotNull(context);
System.out.println(itemService.getItem());
}
}
@@ -0,0 +1,28 @@
package com.baeldung.applicationcontext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ContextConfiguration(classes = TestContextConfig.class)
@ExtendWith(SpringExtension.class)
class MyBeanUnitTest {
@Autowired
MyBean myBean;
@Test
void whenGetApplicationContext_thenReturnApplicationContext() {
assertNotNull(myBean);
ApplicationContext context = myBean.getApplicationContext();
assertNotNull(context);
System.out.printf("ApplicationContext has %d beans %n", context.getBeanDefinitionCount());
}
}
@@ -0,0 +1,11 @@
package com.baeldung.applicationcontext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.baeldung.applicationcontext")
public class TestContextConfig {
}
@@ -0,0 +1,49 @@
package com.baeldung.component.autoproxying;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {EligibleForAutoProxyRandomIntProcessor.class, DataCache.class, RandomIntGenerator.class})
public class EligibleForAutoProxyingIntegrationTest {
private static MemoryLogAppender memoryAppender;
private EligibleForAutoProxyRandomIntProcessor randomIntProcessor;
@Autowired
private DataCache dataCache;
@BeforeClass
public static void setup() {
memoryAppender = new MemoryLogAppender();
memoryAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
Logger logger = (Logger) LoggerFactory.getLogger("org.springframework.context");
logger.setLevel(Level.INFO);
logger.addAppender(memoryAppender);
memoryAppender.start();
}
@Test
public void givenAutowireInBeanPostProcessor_whenSpringContextInitialize_thenNotEligibleLogShouldShowAndGroupFieldPopulated() {
List<ILoggingEvent> notEligibleEvents = memoryAppender.search("Bean 'randomIntGenerator' of type [com.baeldung.component.autoproxying.RandomIntGenerator] " +
"is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)");
assertEquals(0, notEligibleEvents.size());
assertNotEquals(0, dataCache.getGroup());
}
}
@@ -0,0 +1,48 @@
package com.baeldung.component.autoproxying;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class MemoryLogAppender extends ListAppender<ILoggingEvent> {
public void reset() {
this.list.clear();
}
public boolean contains(String string, Level level) {
return this.list.stream()
.anyMatch(event -> event.getMessage().toString().contains(string)
&& event.getLevel().equals(level));
}
public int countEventsForLogger(String loggerName) {
return (int) this.list.stream()
.filter(event -> event.getLoggerName().contains(loggerName))
.count();
}
public List<ILoggingEvent> search(String string) {
return this.list.stream()
.filter(event -> event.getMessage().toString().contains(string))
.collect(Collectors.toList());
}
public List<ILoggingEvent> search(String string, Level level) {
return this.list.stream()
.filter(event -> event.getMessage().toString().contains(string)
&& event.getLevel().equals(level))
.collect(Collectors.toList());
}
public int getSize() {
return this.list.size();
}
public List<ILoggingEvent> getLoggedEvents() {
return Collections.unmodifiableList(this.list);
}
}
@@ -0,0 +1,48 @@
package com.baeldung.component.autoproxying;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {NotEligibleForAutoProxyRandomIntProcessor.class, DataCache.class, RandomIntGenerator.class})
public class NotEligibleForAutoProxyingIntegrationTest {
private static MemoryLogAppender memoryAppender;
private NotEligibleForAutoProxyRandomIntProcessor proxyRandomIntProcessor;
@Autowired
private DataCache dataCache;
@BeforeClass
public static void setup() {
memoryAppender = new MemoryLogAppender();
memoryAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
Logger logger = (Logger) LoggerFactory.getLogger("org.springframework.context");
logger.setLevel(Level.INFO);
logger.addAppender(memoryAppender);
memoryAppender.start();
}
@Test
public void givenAutowireInBeanPostProcessor_whenSpringContextInitialize_thenNotEligibleLogShouldShowAndGroupFieldNotPopulated() {
List<ILoggingEvent> notEligibleEvents = memoryAppender.search("Bean 'randomIntGenerator' of type [com.baeldung.component.autoproxying.RandomIntGenerator] " +
"is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)");
assertEquals(1, notEligibleEvents.size());
assertEquals(0, dataCache.getGroup());
}
}
@@ -0,0 +1,56 @@
package com.baeldung.concurrentrequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher;
/**
* Test need to pause the main thread for up to 60 seconds
*/
@SpringBootTest
@AutoConfigureMockMvc
public class ConcurrentRequestManualTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ProductController controller;
@Test
public void givenContextLoads_thenProductControllerIsAvailable() {
assertThat(controller).isNotNull();
}
@Test
public void givenMultipleCallsRunInParallel_thenAllCallsReturn200() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> performCall("/product/1", status().isOk()));
executor.submit(() -> performCall("/product/2/stock", status().isOk()));
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
}
private void performCall(String url, ResultMatcher expect) {
try {
this.mockMvc.perform(get(url))
.andExpect(expect);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,30 @@
package com.baeldung.version;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = VersionObtainer.class)
public class VersionObtainerUnitTest {
public VersionObtainer version = new VersionObtainer();
@Test
public void testGetSpringVersion() {
String res = version.getSpringVersion();
assertThat(res).isNotEmpty();
}
@Test
public void testGetJdkVersion() {
String res = version.getJdkVersion();
assertThat(res).isNotEmpty();
}
@Test
public void testGetJavaVersion() {
String res = version.getJavaVersion();
assertThat(res).isNotEmpty();
}
}