custom json serializer (Bean injection) - java

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????

From your code I'm assuming you are using Spring. I can think of two reason why field edservice may be null null:
Property vault.encryptdecrypt.provider is not found in its application context.
Bean(s) with given name(s) are not found in its application context.
You can add
#Value("vault.encryptdecrypt.provider") private String provider;
to class MaskSerializer to determine if the property is found - if it is then you'll know that the bean and not the property is missing from the application context. Then you simply need to define that particular bean in that particular context. Otherwise you 'll need to define an appropriate PropertySource to read your property file.
The above is of course assuming that MaskSerializer and LogService beans are in different application contexts. Otherwise the only thing I can think of is that you're doing this:
MaskSerializer maskSerializer = new MaskSerializer();
instead of this (or equivalent with #Resource or #Inject):
#Autowired MaskSerializer maskSerializer;
somewhere in your code.

Related

Not able to pass String to a constructor in Java using Spring

I'm trying to pass parameter to one of constructor of my BBFilter component, however it throws the exception that No beans of String type found. I have autowired the constructor as well. Am I doing anything wrong? Please advise
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(new BBFilter("plan1"));
}
BBFilter
#Component
public class BBFilter implements Filter {
private String planType;
#Autowired
public BBFilter(String planType) { --> Could not autowire. No beans of String type found
this.planType = planType;
}
}
I am assuming you are using Spring. The #Component annotation tells spring to automatically create an Instance of BBFilter as a Bean.
You also annotated the constructor with #Autowired. So Spring searches it's beans for fitting types and injects the automatically on construction. Since you probably didn't define any String bean it cannot autowire the String and throws an exception.
But since you want to create the Filter manually anyways you can simply remove both annotations from your BBFilter Class:
public class BBFilter implements Filter {
private String planType;
public BBFilter(String planType) {
this.planType = planType;
}
}
This should fix the exception but you also can no longer inject it anywhere else (per #Autowire) if needed.
Declare bean of BBFilter like
#Bean
public BBFilter bbFilter() {
return new BBFilter("plan1");
}
And use it in BBBean like this
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(bbFilter());
}
And remove #Component and #Autowired from BBFilter

BeanCreationException error when referencing configuration class inside a service class

I am trying to #Autowire a #Configuration class inside a #Service class. basically my #Configuration class contains mapping to my custom .properties file. When i try to autowire my configuration class inside my service class, BeanCreationException occurs. I am not sure what happen. Just followed the guide on creating Property classes from spring. There must be something i missed out.
Also, when i try to autowire #Configuration class to another #Configuration class, it runs smoothly
Currently, i know that, prop is always null because when i remove prop.getUploadFileLocation() call, everything will be fine. There must be something wrong during autowiring.
Here is my Service class
#Service
public class ImageService {
public static Logger logger = Logger.getLogger(ImageService.class.getName());
#Autowired
MyProperties prop;
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
Here is my Configuration class
#Data
#Configuration
#ConfigurationProperties (prefix = "my")
public class MyProperties {
private String resourceLocation;
private String resourceUrl;
public String getUploadFileLocation() {
return getResourceLocation().replace("file:///", "");
}
public String getBaseResourceUrl() {
return getResourceUrl().replace("**", "");
}
}
And here is where i can successfully use MyProperties
#Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Autowired
MyProperties prop;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(prop.getResourceUrl())
.addResourceLocations(prop.getResourceLocation());
}
}
The issue is that you are trying to use an autowired field to set the value in an inline field assignment.
That means
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
is executed before the prop is autowired, meaning it will always be null
The way to mitigate this would be to use constructor injection instead.
#Service
public class ImageService {
//Fine since you are using static method
public static Logger logger = Logger.getLogger(ImageService.class.getName());
//Not needed if you are only using it to set FILE_UPLOAD_LOCATION
//Allows field to be final
private final MyProperties prop;
//Still final
private final String FILE_UPLOAD_LOCATION;
//No need for #Autowired since implicit on component constructors
ImageService(MyProperties prop){
//Again not needed if you aren't going to use anywhere else in the class
this.prop = prop;
FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
}
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
See this question for why constructor is preferred over #autowired in general
If you need MyProperties bean to be created before StaticResourceConfiguration bean, you can put #ConditionalOnBean(MyProperties.class) as following. Spring will make sure MyProperties is there before processing StaticResourceConfiguration.
#Configuration
#ConditionalOnBean(MyProperties.class)
public class StaticResourceConfiguration implements WebMvcConfigurer {

Dynamically logging in spring framework

Currently I'm having a spring boot application and for each class like SampleClass that I would like to have a log I need to initialize the logger like this:
private static Logger log = LoggerFactory.getLogger(SampleClass.class);
Which means that we need statically send the classname to the getLogger method.
I was thinking of creating a loggable interface and everytime a class implements this interface, it dynamically finds the class name and properly write the log to the outputstream with proper classname.
I googled to find a proper solution but every example is specifically sending the classname in the compile time. Does spring have this ability?
I recommend to use Lombok #log varient in your project, it will automatically set at compile time
If you are using slf4j use #Slf4j
It's best approach and even spring uses internally in some projects
Create a new #Log annotation.
#Documented
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Log {}
Now implement the BeanPostProcessor which gives us the postProcessBeforeInitialization method which allows us to manage a bean before initialization. We search for the #Log annotation and inject an implementation with the LoggerFactory.
#Component
public class LoggerPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
Logger log = LoggerFactory.getLogger(bean.getClass());
ReflectionUtils.makeAccessible(field);
field.set(bean, log);
}
}, new ReflectionUtils.FieldFilter() {
#Override
public boolean matches(Field field) {
return field.isAnnotationPresent(Log.class);
}
});
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
And use the #Log annotation at field level to describe that we want to inject a logger.
#Log
private Logger logger;

How to #autowire some bean into JsonSerializer?

I am using lazy loading with hibernate in my web app.
I would like to load some objects from the database at the parsing stage of the server response
#Component
public class DesignSerializer extends JsonSerializer<Design> {
#Autowired
IDesignService designService; <-- is null
}
Which is totally understandable because DesignSerializer is being instantiated with the "new" operator for each object.
I am sure there is a way to inject my bean into that serializer when ever it is created, I just don't know how.
Can you guys help me or point me in the right direction.
Solution is SpringBeanAutowiringSupport if you are using Spring Framework 2.5+.
public class DesignSerializer extends JsonSerializer<Design> {
#Autowired
IDesignService designService;
}
public DesignSerializer(){
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
...
}
I Hope that help you
We had the same problem with JsonSerializer and Spring autowiring. The solution that worked for us was to make two constructors. One for Spring which sets the dependency as a static field, and another one that is used by the Jackson initialisation.
This works because the Spring dependency injection (autowiring) happens before Jackson initialises the serializer.
#Component
public class MyCustomSerializer extends JsonSerializer<String> {
private static IDesignService designService;
// Required by Jackson annotation to instantiate the serializer
public MyCustomSerializer() { }
#Autowired
public MyCustomSerializer(IDesignService designService) {
this.designService = designService;
}
#Override
public void serialize(String m, JsonGenerator gen, SerializerProvider s) {
gen.writeObject(MyCustomSerializer.designService.method(..));
}
}
I Solved the problem by creating a static field in a different bean and then #Autowire its setter method.
#Service("ToolBox")
#Transactional
public class ToolBox
{
static Logger logger = Logger.getLogger(ToolBox.class);
private static IService service;
#Autowired
public void setService(IService service)
{
ToolBox.service = service;
}
public static IService getService()
{
return ToolBox.service;
}}
like shown in this thread: Can you use #Autowired with static fields?

Accessing DAO Service methods from non managedbeans

I am using Spring 3 and Hibernate 4
How can I use the following in a non ManagedBean
#Inject
EmployeeService employeeService
Or if I would want to access DAO method I have to make that a ManagedBean as
#Named("mymanagedbean")
#ViewAccessScoped
I have a few Converter class and in order to access DAO service methods I had to use that as ManagedBean even though they are not ManagedBeans.
What is the best approach to call DAO service methods?
Thanks
You will need to implement the Spring interface ApplicationContextAware and then set the ApplicationContext. Then you need provide static methods to get the bean instance.
public class SpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context)
throws BeansException {
CONTEXT = context;
}
public static Object getBean(String beanName) { ...}
public static <T> T getBean(Class<T> arg0) {...}
Then in your non-managed bean you can call SpringApplicationContext.getBean method by passing in EmployeeService.class as the argument or the bean name as the argument.
If you want to keep your Converter class clean and use dependency injection (which is highly recommended in order to be able the test the class easily) instead of the class pulling in its dependencies manually, you can use Spring's ability to configure a pre-existing object created outside of the application context. See the related section in Spring's reference documentation here.
Here is a working example (pertinent to zagyi's answer). Application uses Spring Roo and therefore aspectj.
#FacesConverter("example.entity.converter")
#Configurable
public class EntityConverter implements Converter {
#Resource
MyDAO dao;
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
Entity obj;
try {
obj = dao.getEntity(Long.valueOf(value));
} catch( NumberFormatException e ) {
throw new ConverterException( message );
}
return obj;
}
#Override
public String getAsString(FacesContext context, UIComponent component,
Object value) {
Entity obj = (Entity) value;
return (obj != null) ? obj.getId().toString() : "";
}
}
The dao class
#Repository("myDAO")
public class MyDAOImpl implements MyDAO {
...
}
I have managed to get the DAO method in Converter without #Inject using the following and in EmployeeService class which implements Interface I have defined as #Service(value="employeeService")
EmployeeService employeeService =
(EmployeeService)facesContext.getApplication().getELResolver().
getValue(facesContext.getELContext(), null,
"employeeService");

Categories