proper way to use getBean() to create Beans dynamically - spring

Setup :
- have a Several Configuration Class containing Bean definitions for my beans
- I will fetched a List of String from a database containing all the bean names and their corresponding Configuration class I want to instantiate dynamically
currently I will do a loop on the list and then call a method passing the beanName and the Configuration Class containing the bean definition:
private Object getBean(String beanName, Class configurationClass) {
Object bean = null;
AbstractApplicationContext context = new AnnotationConfigApplicationContext(
configurationClass);
bean = context.getBean(beanName);
return bean;
}
I would then use the returned object and used Reflections to invoke specific Methods based on a list I fetched from a database.
Question : Is there a proper way to do this ? because for every bean I want to create , I think performance will be affected.

You can use this in spring 4.1
I found the below example in this post - Spring MVC: How to return image in #ResponseBody?
public ResponseEntity<InputStreamResource> downloadUserAvatarImage(#PathVariable Long userId) {
GridFSDBFile gridFsFile = fileService.findUserAccountAvatarById(userId);
return ResponseEntity.ok()
.contentLength(gridFsFile.getLength())
.contentType(MediaType.parseMediaType(gridFsFile.getContentType()))
.body(new InputStreamResource(gridFsFile.getInputStream()));
}

Related

spring boot component with string parameters

i have a component that reads a configuration value from application.properties and accepts a string parameter in its constructor as such..
#Component
public class Person
{
#Value("${greeting}")
String greeting;
String name;
public Person(String name)
{
this.name = name;
onGreet( greeting + ", " + name );
}
public void onGreet(String message)
{
}
}
I need to instantiate this component as follows and override its "onGreet" event in the calling code as follows:
Person jack = new Person("jack")
{
public void onGreet(String message)
{
System.out.println( message );
}
};
However I end up getting this..
Parameter 0 of constructor in demo11.Person required a bean of type 'java.lang.String' that could not be found.
My application.properties is as follows:
greeting=hello
What am I missing here? Thank you.
It is literally telling you that the only constructor that you have requires a parameter that Spring knows nothing about.
Add a #Value to that String name in the constructor (right before the parameter) like so public Person(#Value("${name}") String name) if you want Spring to initalize it or remove that constructor
EDIT: some more explanation:
Spring is a dependency injection container. Meaning you define beans and let Spring create and inject them for you. Defining beans can be done in several ways (Java configuration, annotations or xml) here you are using annotation way via #Component.
Now that you have defined your bean (aka component) for Spring it will create it. For it to create it it needs to call a constructor. For that you need to provide it with all information necessary for constructor call - meaning all parameters. If parameters are other classes they need to be defined as beans as well (For example via #Component) if they are simple types like String you need to provide #Value for them.
Lastly if you ever use new ... to define Spring managed beans then the whole Spring magic disappears since Spring doesnt know about this bean instantiation anymore and will not autowire anything into it. For all intenses and purposes Spring is not aware of any objects you create with new.

Spring - Retrieve all scanned packages

I'm creating a Spring Starter project and need to get all classes which are marked with a custom annotation. The annotated class is not a spring bean.
My current solution is to use the ClassPathScanningCandidateComponentProvider to find the required classes.
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(CustomAnnotation.class));
candidates = scanner.findCandidateComponents("THE MISSING PACKAGE NAME");
The problem is that I'm currently provide an empty package String so that all packages/classes are scanned which slows the startup down.
I need to access the packages which are scanned by Spring to avoid the scanning of all packages and classes.
Is there a way to retrieve all packages programmatically which are scanned by Spring or is there an alternative solution to retrieve custom annotated classes which are not Spring beans.
Greets
One solution without the need to make a full classpath scan is to use the AutowiredAnnotationBeanPostProcessor:
private List<Class<?>> candidates = new ArrayList<>();
#Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanClass.isAnnotationPresent(YourAnnotation.class)){
candiates.add(beanClass));
System.out.println(beanClass);
return new Object();
}
}
#Bean
public CandiateHolder candidates() {
return new CandidateHolder(candidates);
}
You can check if the bean class which should be instantiated has the required annotation. If its the case you add the class to a property to expose it later as a bean. Instead of returning null you have to return an instance of a new Object. The returned object can be used to wrap the class in a proxy. Cause I don't need an instance I will return a simple new object. Its maybe a dirty hack but it works.
I have to use this kind of hack cause an instantiation of the needed object will result in an runtime error cause it has to be instantiated in the framework I use.

How to inject values to a wicket page using spring?

Is it possible to inject a value to a wicket page using spring?
With #Value it's possible to inject values to a spring bean.
I know the #SpringBean annotation, but this is only for beans.
My workaround is to wrap the value with a spring bean and then inject this with #SpringBean to my wicket page. Is there a better way to do this?
We have solved this problem using getter & setter in our custom child of WebApplication. This child is standard Spring bean and is configured in spring's configuration.
Otherwise you have to create some "config" bean.
You can write a Wicket resource loader to load spring values, and then those values will be resolved like regular wicket messages. If instead you need it within the body of the wicket class to do some business logic, that may be an opportunity to refactor that logic outside of the view layer.
Here's what the resource loader looks like:
public class SpringPropertiesResourceLoader
implements IStringResourceLoader
{
public SpringPropertiesResourceLoader()
{
}
#Override
public String loadStringResource(Class<?> clazz, String key, Locale locale, String style, String variation)
{
return loadStringResource(key);
}
#Override
public String loadStringResource(Component component, String key, Locale locale, String style, String variation)
{
return loadStringResource(key);
}
private String loadStringResource(String key)
{
try
{
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(WebPortalApplication.get().getServletContext());
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
String rv = beanFactory.resolveEmbeddedValue("${" + key + "}");
return rv;
}
catch (IllegalArgumentException iae)
{
// no property with the name - move along
return null;
}
}
}
Then add that to your application in init():
getResourceSettings().getStringResourceLoaders().add(new SpringPropertiesResourceLoader());

Customizing spring security requestmap in grails 2.3.5

I am using Grails : 2.3.5
and Spring Security Core plugin : 1.2.7.3
In Grails Spring Security RequestMap is a separate table but in my application I want to use the requestMap concept with the existing table.
I have a RolePermissionMap table is there and I want to use this table for the RequestMap.
class Role{
Long id
String name
String description
}
class Permission{
Long id
String name
String description
String requestUrl
}
class RolePermissionMap {
Long id
Role role
Permission permission
}
Now I am overriding the loadRequestmaps() method by extending the RequestmapFilterInvocationDefinition class like below
class RolePermissionMapFilterInvocation extends RequestmapFilterInvocationDefinition {
#Override
protected Map<String, String> loadRequestmaps() {
Map<String, String> data = new HashMap<String, String>();
for (Object requestmap : ReflectionUtils.loadAllRequestmaps()) {
// Original code
//String urlPattern = ReflectionUtils.getRequestmapUrl(requestmap);
//String configAttribute = ReflectionUtils.getRequestmapConfigAttribute(requestmap);
//data.put(urlPattern, configAttribute);
// modified code
Permission permission = ReflectionUtils.getRequestmapUrl(requestmap);
Role role = ReflectionUtils.getRequestmapConfigAttribute(requestmap);
data.put(permission.getRequestUrl(), role.getName());
}
return data;
}
}
Then I will add this bean in resources.groovy
beans = {
objectDefinitionSource(RolePermissionMapFilterInvocation)
}
I am also trying to override the ReflectionUtils class also for getting the return types of getRequestmapUrl(requestmap) and getRequestmapConfigAttribute() methods also as required
When I run with this approach am getting exception below
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'objectDefinitionSource': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: url matcher is required
for resolving the url matcher I added a bean in resources.groovy but it failed
Do I need to create a bean with urlMaper or need to mention ReflectionUtils class any where ?
Please show me a way.. Thanks in Advance
The plugin expects the url field in your request map class to be a String, in order to use a different type you'd have to subclass RequestMapFilterInvocationDefinition to extract the URL patterns correctly, and install your custom class as the bean named objectDefinitionSource in your app's resources.groovy to replace the default bean definition supplied by SpringSecurityCoreGrailsPlugin.groovy in its doWithSpring.

Spring container - annotation for null argument

In my application that uses Spring container I created my own annotation, and I wanted at runtime get Class objects of classes that are annotated with my annotation. For this I wanted to utilize Spring container.
In my .xml configuration file I put
<context:component-scan base-package="some.package" >
<context:include-filter type="annotation" expression="some.package.Question" />
</context:component-scan>
so the classes that are annotated with my Question annotation are detected by Spring. Problem is that those classes don't have no parameter constructor, so now I have 2 options:
Define no-parameter constructor in those classes
Define the beans in .xml and use constructor-arg
but is it possible to annotate constructor arguments with some annotation, so Spring will know that it needs to pass null value during creation of a bean?
Also those beans will have prototype scope, and from the point of view of an application the contents of an constructor arguments are not known during the creation of a bean.
EDIT:
I had to use #Value("#{null}") for annotation constructor arguments
I think your first suggestion of using a no-arg constructor sounds cleaner - the reason is that the object created is, from your perspective, being considered properly initialized even though the instance variables have null values - this can be indicated by having a default constructor
If it cannot be changed, your approach of using #Value("#{null}") also works, I was able to test out in a test case:
#MyAnnotation
public class Component1 {
private String message;
#Autowired
public Component1(#Value("#{null}") String message){
this.message = message;
}
public String sayHello(){
return this.message;
}
}
This may not be what you're looking for, but if you want to re-use Spring's classpath scanner and wrap it in your own implementation, you can use the following;
Class annotation = [your class here ];
String offsetPath = [your path here ];
// Scan a classpath for a given annotation class
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
// MZ: Supply the include filter, to filter on an annotation class
scanner.addIncludeFilter(new AnnotationTypeFilter(annotation));
for (BeanDefinition bd : scanner.findCandidateComponents(offsetPath))
{
String name = bd.getBeanClassName();
try
{
Class classWithAnnotation = Class.forName(name);
}
catch (Exception e)
{
//Logger.fatal("Unable to build sessionfactory, loading of class failed: " + e.getMessage(), e);
return null;
}

Resources