I have a interface which cntaining two implementations.
public interface IEncryptDecryptService {
String encrypt(String text);
String decrypt(String text);
}
one class is
#Service("SunJks")
public class GeneralEncryptDecryptServiceImpl implements
IEncryptDecryptService {
public String encrypt{
}
public String decrypt{
}
}
another class is
#Service("SafenetHsm")
public class SafenetHsmEncryptDecryptServiceImpl implements
IEncryptDecryptService {
public String encrypt{
}
public String decrypt{
}
}
I want to inject one of two classes in another class.
#Component
public class LogService implements ILogService {
#Resource(name = "${vault.encryptdecrypt.provider}")
private IEncryptDecryptService edservice;
public display{
edservice.encrypt("***");
}
This is the class where i need two inject the one of the two beans.
In application.properties i have configured that
#Provider Configurer
vault.encryptdecrypt.provider=SunJks
then "GeneralEncryptDecryptServiceImpl"is injected.
#Provider Configurer
vault.encryptdecrypt.provider=SafenetHsm
then SafenetHsmEncryptDecryptServiceImpl is injected into the "LogService" class.
It works fine.
and if i implement same thing in Custom JsonSerializer class it is not working,bean is not injected.
#Component
public class MaskSerializer extends JsonSerializer<Xclass> {
#Resource(name = "${vault.encryptdecrypt.provider}")
private IEncryptDecryptService edservice;
#Override
public void serialize(Xclass value, JsonGenerator gen,
SerializerProvider provider) throws IOException {
String str = value.getPersistenceValue();
String strr = edservice.encrypt(str);
gen.writeStartObject();
gen.writeFieldName(strr);
gen.writeEndObject();
}
i am getting nullpointer exception at edservice.encrypt(str) in above class.
Bean is not injected????
Related
I have been trying to create a custom scope in Spring Framework, but I fail to understand how is the scope actually instantiated and destroyed.
Assuming I want to create an EventScope and I have a com.example.EventHandler.handleEvent(Event event) method that handles an incoming event.
How do I ensure that every Event starts/stops a scope when it is being handled?
If I have several EventScoped beans wired in, How do I make sure they are using the same scope instance during an event? It seems like a new EventScopeImpl would be created for every bean?
If I have to use a ThreadLocal or some other static context, what is even the point of using a custom scope when I can use the ContextHolder class directly?
My code is as follows?
EventScopeImpl.java
public class EventScopeImpl implements Scope {
private final Map<String, Object> scopedObjects
= Collections.synchronizedMap(new HashMap<String, Object>());
private final Map<String, Runnable> destructionCallbacks
= Collections.synchronizedMap(new HashMap<String, Runnable>());
#Override
public Object get(final String name, final ObjectFactory<?> objectFactory) {
if(!scopedObjects.containsKey(name)) {
scopedObjects.put(name, objectFactory.getObject());
}
return scopedObjects.get(name);
}
#Override
public Object remove(final String name) {
Optional.ofNullable(destructionCallbacks.remove(name)).ifPresent(Runnable::run);
return scopedObjects.remove(name);
}
#Override
public void registerDestructionCallback(final String name, final Runnable callback) {
destructionCallbacks.put(name, callback);
}
#Override
public Object resolveContextualObject(final String key) {
return EventContextHolder.instance().getValue(key);
}
#Override
public String getConversationId() {
return null;
}
}
EventScope.java
#Qualifier
#Scope(value = "event", proxyMode = ScopedProxyMode.TARGET_CLASS)
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface EventScope{}
EventContextHolder.java
public class EventContextHolder{
#Getter
#Accessors(fluent = true)
public static final EventContextHolder instance = new EventContextHolder();
private final static ThreadLocal<Context> context = ThreadLocal.withInitial(Context::new);
private EventContextHolder(){}
public void setValue(final String key, final Object value){
context.get().data().put(key,value);
}
public Object getValue(final String key){
return context.get().data().get(key);
}
public void clear(){
context.get().data().clear();
}
private static class Context{
#Accessors(fluent = true)
#Getter
private final ConcurrentHashMap<String,Object> data = new ConcurrentHashMap<>();
}
}
EventAspect.java
#Aspect
#Component
public class EventAspect {
#Pointcut("execution(com.example.EventHandler.handleEvent(..))")
public void eventHandlerMethod() {};
#Around("eventHandlerMethod()")
public Object startMessageContext(ProceedingJoinPoint pjp) throws Throwable {
final Event event;
if(pjp.getArgs() > 0 && Event.class.isInstance(pjp.getArgs()[0]){
event = (Event)pjp.getArgs()[0];
}
#Cleanup("clear") EventContextHolder context = EventContextHolder.instance();
context.setValue("event",event);
Object retVal = pjp.proceed();
return retVal;
}
}
EventContext.java
#RequiredArgsConstructor
#Getter
#Component
#EventScope
#Lazy
public class EventContext {
#Lazy
#Value("#{event}")
private Event event;
}
EventScopeConfiguration.java
#Configuration
public class EventScopeConfiguration {
#Bean
public BeanFactoryPostProcessor eventScopeBeanFactoryPostProcessor() {
return beanFactory -> beanFactory.registerScope(
"event", new EventScopeImpl());
}
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I have an abstract class with some configuration properties value which are set using #Value. I want to reuse the abstract class but with another set of configuration properties. The issue is that, those properties value have already been set in the abstract class and all of the concrete classes have inherited it.
I have thought about:
creating another set of config values in the abstract class, but that seems to be creating duplicate, but this is not quite extensible when in future there is yet a third set of config values.
changing the accessibly of the config value in the abstract class from private to protected and have the concrete class to override it. But I'm not sure this kind of overriding is good as it seems create confusion as to what is the actual config value.
create another abstract class which is similar as "AbstractService" but injecting the different set of config value using #Value. This also seems to create duplication.
public abstract class AbstractService {
#Value("${config1}")
private String config1;
#Value("${config2}")
private String config2;
public void serviceMethod() {
//using config1 and config 2 values
}
}
public class concreteServiceA extends AbstractService {
public void serviceA() {
// using serviceMethod in the abstract class
}
}
public class concreteServiceB extends AbstractService {
public void serviceB() {
// using serviceMethod in the abstract class
}
}
Would it be a good way if using constructor to pass the required parameters in the abstract class, and let the concrete classes to use constructor injection and #Value to set those values ? though if there are long list of config values this may not scale well.
public abstract class AbstractService {
private String config1;
private String config2;
public AbstractService(String config1, String config2) {
this.config1 = config1;
this.config2 = config2;
}
public void serviceMethod() {
//using config1 and config2 values
}
}
public concreteServiceA extends AbstractService {
public concreteServiceA(#Value("${config1}") String config1,
#Value("${config2}") String config2) {
super(config1, config2);
}
public void serviceA() {
//using serviceMethod in the abstract class
}
}
public concreteServiceB extends AbstractService {
public concreteServiceB(#Value("${configB1}") String config1,
#Value("${configB2}") String config2) {
super(config1, config2);
}
public void serviceB() {
//using serviceMethod in the abstract class
}
}
You can go like following:
public abstract class AbstractService {
public void serviceMethod() {
String config1 = getConfig1();
String config2 = getConfig2();
//using config1 and config 2 values
}
public abstract String getConfig1();
public abstract String getConfig2();
}
public class concreteServiceA extends AbstractService {
#Value("${config1}") private String config1;
#Value("${config2}") private String config2;
public String getConfig1(){
return config1;
}
public String getConfig2(){
return config2;
}
public void serviceA() { // using serviceMethod in the abstract class }
}
public class concreteServiceB extends AbstractService {
#Value("${config1.1}") private String config1;
#Value("${config2.1}") private String config2;
public String getConfig1(){
return config1;
}
public String getConfig2(){
return config2;
}
public void serviceB() { // using serviceMethod in the abstract class }
}
You could either use setter injection or (probably more elegant) constructor injection like this:
public abstract class AbstractService {
protected AbstractService(String config1, String config2) {
this.config1 = config1;
this.config2 = config2;
}
private String config1;
private String config2;
public void serviceMethod() {
//using config1 and config 2 values
}
}
public class ConcreteServiceA extends AbstractService {
public ConcreteServiceA(#Value("${config1a}") String config1, #Value("${config2a}") String config2) {
super(config1, config2);
}
public void serviceA() {
// using serviceMethod in the abstract class
}
}
public class ConcreteServiceB extends AbstractService {
public ConcreteServiceB(#Value("${config1b}") String config1, #Value("${config2b}") String config2) {
super(config1, config2);
}
public void serviceB() {
// using serviceMethod in the abstract class
}
}
But if you have lots of values you can also use setter injection and override the setters in each subclass. Or you can still use constructor injection but pass a container class holding the config like this:
public class ServiceConfig {
private String config1;
private String config2;
// getters, setters and more properties
}
Then pass it like this
public abstract class AbstractService {
private ServiceConfig config;
protected AbstractService(ServiceConfig config) {
this.config = config;
}
}
public class ConcreteServiceA extends AbstractService {
public ConcreteServiceA(#Value("${configA}") ServiceConfig config) {
super(config);
}
}
You can externalize your properties to specific beans which will be autowired to the concrete classes.
Spring annotation #ConfigurationProperties allows you to initialise simple POJO properties based on properties prefix.
First create your POJO which we will inject in the concrete services :
public class ServiceProperties {
private String config1;
private String config2;
//getters and setters
}
Then create a configuration class in a package scanned by spring :
#Configuration
public class ServicePropertiesConfiguration {
#Bean
#ConfigurationProperties(prefix = "service-a")
public ServiceProperties serviceAProperties() {
return new ServiceProperties();
}
#Bean
#ConfigurationProperties(prefix = "service-b")
public ServiceProperties serviceBProperties() {
return new ServiceProperties();
}
}
As you can see, prefix tells to spring where he has to search the properties. Your application.properties will look like this :
service-a.config1=serviceAConfig1
service-a.config2=serviceAConfig2
service-b.config1=serviceBConfig1
service-b.config2=serviceBConfig2
At this stage, you will have two beans of type ServiceProperties with specific values inside
The abstract service looks like this :
public abstract class AbstractService {
private final ServiceProperties serviceProperties;
protected AbstractService(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
public void serviceMethod() {
//using config1 and config 2 values
// serviceProperties.getConfig1();
// serviceProperties.getConfig2();
}
}
In the concrete service, you have to use #Qualifier annotation with name of created bean
#Service
public class ConcreteServiceA extends AbstractService{
public ConcreteServiceA(#Qualifier("serviceAProperties") ServiceProperties serviceProperties) {
super(serviceProperties);
}
}
#Service
public class ConcreteServiceB extends AbstractService{
protected ConcreteServiceB(#Qualifier("serviceBProperties") ServiceProperties serviceProperties) {
super(serviceProperties);
}
}
I need to get the bean from the factory by name.
I wonder if there is a more elegant way to deal with this problem?
My working code now looks like this. This is my interface service and "factory"
public interface GreetingService {
void getGreeting(String name);
}
public interface GreetingServiceFactory {
GreetingService getGreetingService(String region);
}
Implementation greetingService:
#Service
public class EnglishGreetingServiceImpl implements GreetingService {
#Override
public void getGreeting(String name) {
System.out.println("Hello " + name);
}
}
#Service
public class GermanGreetingServiceImpl implements GreetingService {
#Override
public void getGreeting(String name) {
System.out.println("Willkommen " + name);
}
}
Implementation factory:
#Service
public class GreetingServiceFactoryImpl implements GreetingServiceFactory {
private Map<String, GreetingService> greetingBeanMap;
#Autowired
#Qualifier("germanGreetingServiceImpl")
private GreetingService germanGreetingService;
#Autowired
#Qualifier("englishGreetingServiceImpl")
private GreetingService englishGreetingService;
#PostConstruct
public void init () {
greetingBeanMap = new HashMap<>();
greetingBeanMap.put("en", englishGreetingService);
greetingBeanMap.put("de", germanGreetingService);
}
#Override
public GreetingService getGreetingService(String region) {
return greetingBeanMap.get(region);
}
}
Main class with example code where I receive bean after some name
#SpringBootApplication
public class SpringFactoryApplication implements CommandLineRunner {
#Autowired
private GreetingServiceFactory greetingServiceFactory;
public static void main(String[] args) {
SpringApplication.run(SpringFactoryApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
String config1 = "en";
GreetingService english = greetingServiceFactory.getGreetingService(config1);
english.getGreeting("John");
String config2 = "de";
GreetingService deutsch = greetingServiceFactory.getGreetingService(config2);
deutsch.getGreeting("Hans");
}
}
In your above code, this piece of code is completely redundant
#Autowired
#Qualifier("germanGreetingServiceImpl")
private GreetingService germanGreetingService;
#Autowired
#Qualifier("englishGreetingServiceImpl")
private GreetingService englishGreetingService;
#PostConstruct
public void init () {
greetingBeanMap = new HashMap<>();
greetingBeanMap.put("en", englishGreetingService);
greetingBeanMap.put("de", germanGreetingService);
}
this piece of code can be replaced by
#Autowired
private Map<String, GreetingService> greetingBeanMap;
When you declare like this, spring will search for all implementations of GreetingService interface and inject into your map, with the key as the bean name. i.e. the greetingBeanMap will have key's as germanGreetingServiceImpl and englishGreetingServiceImpl and value as the bean's itself.
If you want to make the key's as "en" and "de" instead of bean names, then you can name the beans as "en" and "de". Like this
#Service("en")
public class EnglishGreetingServiceImpl implements GreetingService {
......
}
#Service("de")
public class GermanGreetingServiceImpl implements GreetingService {
......
}
I'm planning to create my objects in my Spring MVC using the below setup but How can I inject values to my MyService ie; instantiate the object with default value...
public class MyController {
private MyService myService;
#Autowired
public void setMyService(MyService aService) { // autowired by Spring
this.myService = aService;
}
#RequestMapping("/blah")
public String someAction()
{
// do something here
myService.foo();
return "someView";
}
}
MyService
class Myservice(){
String servicename;
public Myservice(servicename){
this.servicename = servicename;
}
}
Without Spring
MyService first = new MyService("firstservice");
MyService second = new MyService("secondservice");
Just declare your constructor with #Autowired to mark it as the constructor to use and its parameter with #Value to indicate the value to use.
#Autowired
public Myservice(#Value("example") String servicename){
Or use a placeholder
#Autowired
public Myservice(#Value("${placeholder.key}") String servicename){
Firstly, your exam are wrong on using Spring DI. To inject Myservice type to another You should declare MyService as a interface instead:
interface Myservice(){
public void foo();
}
After that, declare an implementation of this interface (again, use Spring DI to inject String type):
class BarService() implements Myservice{
String servicename;
#Autowired
public Myservice(#Value("servicename") String servicename){
this.servicename = servicename;
}
public void foo(){
}
}
let imagine I have per entity a repository class (spring data jpa) for database access and a service class. The dependencies are managed by spring framework. Every service method does in most cases the same, so there is mainly code duplication:
public class NewsService {
#Inject
private NewsRepository newsRepository;
public void add(News news) {
// do some validation
newsRepository.save(news);
}
}
public class UserService {
#Inject
private UserRepository userRepository;
public void add(User user) {
// do some validation
userRepository.save(user);
}
}
Now i thought about creating an abstract class like this:
public abstract class AbstractService<T> {
private UnknownRepository unknownRepository;
public void add(T entity) {
// do some validation
unknownRepository.save(entity);
}
}
public class NewsService extends AbstractService<News> {
}
public class UserService extends AbstractService<User> {
}
My problem: How can i overwrite the repository used inside the abstract class based on my entities?
You can replace the UnknownRepository field with an abstract method and a type parameter:
// R is the type of the repository
public abstract class AbstractService<T,R extends BaseRepository> {
protected abstract R getRepository();
public void add(T entity) {
getRepository().save(entity);
}
}
And inject the specific repository to the implementations of this class:
public class NewsService extends AbstractService<News, NewsRepository> {
#Inject private NewsRepository newsRepository;
#Override
public NewsRepository getRepository() {
return newsRepository;
}
// the inherited add() method works now
}