Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gp-138 bean post processor new exercise MAIN #26

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions 3-0-spring-framework/bean-post-processor/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# <img src="https://raw.githubusercontent.com/bobocode-projects/resources/master/image/logo_transparent_background.png" height=50/>Bean Post Processor exercise
Improve your *Spring* advanced skills 💪
### Task
Implement automatic String trimming functionality. So if I pass " Hello " as an argument to my bean’s method, or return it from the bean’s method, it gets automatically trimmed to "Hello".

- create annotation @Trimmed that you can put on class

- create annotation @EnableStringTrimming that will enable automatic String trimming for all beans that are annotated with @Trimmed

- create TrimmedAnnotationBeanPostProcessor that will check for beans that are marked with @Trimmed,

- create a proxy of those classes, and override methods. Proxy methods should:

- trim all String arguments

- trim all String return values

- extract TrimmedAnnotationBeanPostProcessor into a separate StringTrimmingConfiguration that is imported by @EnableStringTrimming

To verify your configuration, run `BeanPostProcessorTest.java`


### Pre-conditions ❗
You're supposed to be familiar with *Spring*

### How to start ❓
* Just clone the repository and start implementing the **todo** section, verify your changes by running tests
* If you don't have enough knowledge about this domain, check out the [links below](#Related-materials-ℹ)
* Don't worry if you got stuck, checkout the **exercise/completed** branch and see the final implementation

### Related materials ℹ
todo

---
#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-course/tree/main/0-0-intro#introduction)

##
<div align="center"><img src="https://raw.githubusercontent.com/bobocode-projects/resources/master/animation/GitHub%20Star_3.gif" height=50/></div>
27 changes: 27 additions & 0 deletions 3-0-spring-framework/bean-post-processor/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>3-0-spring-framework</artifactId>
<groupId>com.bobocode</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>bean-post-processor</artifactId>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.bobocode.annotation;

import com.bobocode.util.StringTrimmingConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Configuration
@Import(StringTrimmingConfiguration.class)
public @interface EnableStringTrimming {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.bobocode.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Trimmed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.bobocode.config;

import com.bobocode.annotation.EnableStringTrimming;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
* Configure the application for using @Trimmed annotation and corresponding logic.
*/

@Configuration
@ComponentScan(basePackages = "com.bobocode.service")
@EnableStringTrimming
public class ApplicationConfig {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.bobocode.service;

import com.bobocode.annotation.Trimmed;
import org.springframework.stereotype.Service;

/**
* Configure the service to provide trimming process.
*/

@Service
@Trimmed
public class TextService {
public String savedText;
private final static String AVAILABLE_TEXT = " Who cares about tabbing? ";

public void saveText(String text){
savedText = text;
}

public String getAvailableText(){
return AVAILABLE_TEXT;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.bobocode.util;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class StringTrimmingConfiguration {

@Bean
public BeanPostProcessor trimmedAnnotationBeanPostProcessor(){
return new TrimmedAnnotationBeanPostProcessor();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.bobocode.util;

import com.bobocode.annotation.Trimmed;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.reflect.Method;
import java.util.Arrays;

public class TrimmedAnnotationBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> beanClass = bean.getClass();
if (beanClass.isAnnotationPresent(Trimmed.class)) {
return createTrimmedProxy(beanClass);
}
return bean;
}

private Object createTrimmedProxy(Class<?> beanClass) {
var enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setInterfaces(beanClass.getInterfaces());
MethodInterceptor interceptor = (Object obj, Method method, Object[] args, MethodProxy proxy) -> {
Object[] arguments = Arrays.stream(args)
.filter(arg -> arg instanceof String)
.map(arg -> ((String) arg).trim())
.toArray();

if (method.getReturnType().equals(String.class)) {
String invokeSuper = (String) proxy.invokeSuper(obj, arguments);
return (String) invokeSuper.trim();
}
return proxy.invokeSuper(obj, arguments);
};
enhancer.setCallback(interceptor);
return beanClass.cast(enhancer.create());
}
}
Loading