When I define my managed bean as a CDI bean (#Named) it is not shown by the ui:debug popup. If I change the definition to a JSF #ManagedBean it shows up in the scoped variables just fine.
Is there anything extra I need to do to make this work?
I am using Mojarra 2.1.
CDI managed beans are not stored as direct attributes of the request/session/application scope. They're abstracted away behind the CDI context, for which it's in turn implementation dependent (e.g. Weld vs OpenWebBeans vs others) how exactly they're referenced in the scope. The <ui:debug> doesn't offer any builtin facilities to display active CDI managed beans (yet?).
Your best bet is obtaining them manually. You can use the following utility method for that (which will be available in upcoming OmniFaces 1.7's Beans utility class):
public static Map<Object, String> getActiveReferences(BeanManager beanManager, Class<? extends Annotation> scope) {
Map<Object, String> activeReferences = new HashMap<Object, String>();
Set<Bean<?>> beans = beanManager.getBeans(Object.class);
Context context = beanManager.getContext(scope);
for (Bean<?> bean : beans) {
Object reference = context.get(bean);
if (reference != null) {
activeReferences.put(reference, bean.getName());
}
}
return Collections.unmodifiableMap(activeReferences);
}
Here's how you can use it:
#Inject
private BeanManager manager;
public void collect() {
Map<Object, String> requestScopedBeans = Beans.getActiveReferences(manager, RequestScoped.class);
// Map key represents the instance and map value represents the managed bean name, if any.
// ...
}
Keep in mind that this is a relatively expensive job. So really use it for debugging only.
Related
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 6 years ago.
I was able to use RestTemplate and autowire it. However I want to move my rest template related part of code into another class as follows:
public class Bridge {
private final String BASE_URL = "http://localhost:8080/u";
#Autowired
RestTemplate restTemplate;
public void addW() {
Map<String, String> x = new HashMap<String, String>();
W c = restTemplate.getForObject(BASE_URL + "/device/yeni", W.class, x);
System.out.println("Here!");
}
}
And at another class I call it:
...
Bridge wb = new Bridge();
wb.addW();
...
I am new to Spring and Dependency Injection terms. My restTemplate variable is null and throws an exception. What can I do it how to solve it(I don't know is it related to I use new keyword)?
Using Bridge wb = new Bridge() does not work with dependency injection. Your restTemplate is not injected, because wb in not managed by Spring.
You have to make your Bridge a Spring bean itself, e.g. by annotation:
#Service
public class Bridge {
// ...
}
or by bean declaration:
<bean id="bridge" class="Bridge"/>
Just to add further to Jeha's correct answer.
Currently, by doing
Bridge wb = new Bridge();
Means that, that object instance is not "Spring Managed" - I.e. Spring does not know anything about it. So how can it inject a dependency it knows nothing about.
So as Jeha said. Add the #Service annotation or specify it in your application context xml config file (Or if you are using Spring 3 you #Configuration object)
Then when the Spring context starts up, there will be a Singleton (default behavior) instance of the Bridge.class in the BeanFactory. Either inject that into your other Spring-Managed objects, or pull it out manually e.g.
Bridge wb = (Bridge) applicationContext.getBean("bridge"); // Name comes from the default of the class
Now it will have the dependencies wired in.
If you want to use new operator and still all dependency injected, then rather than making this a spring component (by annotating this with #Service), make it a #Configurable class.
This way even object is instantiated by new operator dependencies will be injected.
Few configuration is also required. A detailed explanation and sample project is here.
http://spring-framework-interoperability.blogspot.in/2012/07/spring-managed-components.html
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.
I would like to build a Spring application, where new components can be added easily and without much configuration. For example: You have different kinds of documents. These documents should be able to get exported into different fileformats.
To make this functionality easy to maintain, it should (basically) work the following way:
Someone programs the file format exporter
He/ She writes a component, which checks if the file format exporter is licensed (based on Spring Conditions). If the exporter is licensed a specialized Bean is injected in the application context.
The "whole rest" works dynamically based on the injected beans. Nothing needs to be touched in order to display it on the GUI, etc.
I pictured it the following way:
#Component
public class ExcelExporter implements Condition {
#PostConstruct
public void init() {
excelExporter();
}
#Bean
public Exporter excelExporter(){
Exporter exporter= new ExcelExporter();
return exporter;
}
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
In order to work with those exporters (display them, etc.) I need to get all of them. I tried this:
Map<String, Exporter> exporter =BeanFactoryUtils.beansOfTypeIncludingAncestors(appContext, Exporter.class, true, true);
Unfortunate this does not work (0 beans returned). I am fairly new to this, would anyone mind to tell me how this is properly done in Spring? Maybe there is a better solution for my problem than my approach?
You can get all instances of a given type of bean in a Map effortlessly, since it's a built in Spring feature.
Simply autowire your map, and all those beans will be injected, using as a key the ID of the bean.
#Autowired
Map<String,Exporter> exportersMap;
If you need something more sophisticated, such as a specific Map implementation or a custom key. Consider defining your custom ExporterMap, as follows
#Component
class ExporterMap implements Map{
#Autowired
private Set<Exporter> availableExporters;
//your stuff here, including init if required with #PostConstruct
}
How does one port from
<sec:global-method-security secured-annotations="disabled">
<sec:protect-pointcut expression='execution(* x.y.z.end*(..))' access='...' />
to spring java-config
#EnableGlobalMethodSecurity
#Configuration
public class MyConfiguration extends WebSecurityConfigurerAdapter {
?
There is a simmilar question here http://forum.spring.io/forum/spring-projects/security/726615-protect-pointcut-in-java-configuration
There's a workaround for it. The security points information is kept in MethodSecurityMetadataSource implementations (which are then used by MethodInterceptor) so we have to create an additional MethodSecurityMetadataSource. As mentioned in the spring forum post the xml pointcut configuration is kept in MapBasedMethodSecurityMetadataSource and processed by ProtectPointcutPostProcessor. we also need an instance of ProtectPointcutPostProcessor. Unfortunately this class is final and package-private so there are 2 options:
create your own class and copy/paste the whole content of the original one (that's what I did)
change the class modifiers with reflection and create an instance of the original one (haven't done that so no idea if it would work fine)
then create the following beans in your context:
#Bean
public Map<String, List<ConfigAttribute>> protectPointcutMap() {
Map<String, List<ConfigAttribute>> map = new HashMap<>();
// all the necessary rules go here
map.put("execution(* your.package.service.*Service.*(..))", SecurityConfig.createList("ROLE_A", "ROLE_B"));
return map;
}
#Bean
public MethodSecurityMetadataSource mappedMethodSecurityMetadataSource() {
// the key is not to provide the above map here. this class will be populated later by ProtectPointcutPostProcessor
return new MapBasedMethodSecurityMetadataSource();
}
// it's either the original spring bean created with reflection or your own copy of it
#Bean
public ProtectPointcutPostProcessor pointcutProcessor() {
ProtectPointcutPostProcessor pointcutProcessor = new ProtectPointcutPostProcessor((MapBasedMethodSecurityMetadataSource) mappedMethodSecurityMetadataSource());
pointcutProcessor.setPointcutMap(protectPointcutMap());
return pointcutProcessor;
}
we've created the necessary beans, now we have to tell spring to use them. I'm assuming you're extending GlobalMethodSecurityConfiguration. by default it creates DelegatingMethodSecurityMetadataSource which contains a list of other MethodSecurityMetadataSources. Depending on what you want to achieve you have following options:
if you want to keep all the other MethodSecurityMetadataSources (like the ones for parsing the #Secured annotations) you can extend the list in the delegating metadata source by overriding the following method:
#Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return mappedMethodSecurityMetadataSource();
}
it would inject it on first place in the list though which may cause some problems.
if you want to keep the other sources but want yours to be the last in the list then override the following method:
#Override
public MethodSecurityMetadataSource methodSecurityMetadataSource() {
DelegatingMethodSecurityMetadataSource metadataSource = (DelegatingMethodSecurityMetadataSource) super.methodSecurityMetadataSource();
metadataSource.getMethodSecurityMetadataSources().add(mappedMethodSecurityMetadataSource());
return metadataSource;
}
if you want your source to be the only one (you don't want to use #Secured or any other annotations) then you can override the same method, just with different content
#Override
public MethodSecurityMetadataSource methodSecurityMetadataSource() {
return mappedMethodSecurityMetadataSource();
}
that's it! I hope it will help
I followed #marhewa comments and have been able to use the Spring version of class ProtectPointcutPostProcessor by defining the following bean
/**
* Needed to use reflection because I couldn't find a way to instantiate a
* ProtectPointcutPostProcessor via a BeanFactory or ApplicationContext. This bean will process
* the AspectJ pointcut defined in the map; check all beans created by Spring; store the matches
* in the MapBasedMethodSecurityMetadataSource bean so Spring can use it during its checks
*
* #return
* #throws Exception
*/
#Bean(name = "protectPointcutPostProcessor")
Object protectPointcutPostProcessor() throws Exception {
Class<?> clazz =
Class.forName("org.springframework.security.config.method.ProtectPointcutPostProcessor");
Constructor<?> declaredConstructor =
clazz.getDeclaredConstructor(MapBasedMethodSecurityMetadataSource.class);
declaredConstructor.setAccessible(true);
Object instance = declaredConstructor.newInstance(pointcutMethodMetadataSource());
Method setPointcutMap = instance.getClass().getMethod("setPointcutMap", Map.class);
setPointcutMap.setAccessible(true);
setPointcutMap.invoke(instance, pointcuts());
return instance;
}
This way I don't need to duplicate the code of this Spring class.
Cheers
I am having a series of odd errors in testing and deployment. They seem to indicate that some of my beans are not loading into the context, despite them being defined in applicationContext.xml.
Is there any way to check during testing which beans have actually been loaded? Or to find a complete list of beans loaded at run time?
Thanks,
b
At startup, Spring logs at info level the names of all the beans being loaded by a context. Or in code, you can use getBeanDefinitionNames() to get all the bean names.
if there is more than one context say if you are using spring mvc you can use something more powerful like this.
public class SampleContextApplicationListener implements ApplicationListener<ApplicationContextEvent> {
private Map<String,ApplicationContext> contextMap = new Hashtable<String,ApplicationContext>();
#Override
public void onApplicationEvent(ApplicationContextEvent event) {
if( event instanceof ContextStartedEvent || event instanceof ContextRefreshedEvent){
this.getContextMap().put(event.getApplicationContext().getDisplayName(), event.getApplicationContext());
}
}
public Map<String,ApplicationContext> getContextMap() {
return contextMap;
}
}
You can then inject the listener where it is needed, and extract the map of contextens and then interogate it for all its bean, using the getBeanDefinitionNames()
#Autowired
private StatusTestsApplicationListener listener;