From the 7.6 release notes
Declarative format is now using "vaadin-" as a default prefix instead of the "v-" prefix used in 7.5. This default can be changed in deployment configuration.
How can we configure this prefix? I'm having trouble locating the setting, I'd guess that it's an "InitParameter" but I can't seem to locate a list. I don't see it mentioned on DeploymentConfiguration classes either. annotation based/javaconfig preferred, but I could probably reverse an XML.
I "believe" this will work in Spring, though on reflection I'm not sure we actually use this feature.
public class VaadinWebApplicationInitializer implements WebApplicationInitializer
{
#Override
public void onStartup( final ServletContext servletContext ) throws ServletException
{
Dynamic dynamic = servletContext.addServlet( "Vaadin Application Servlet", ApplicationServlet.class );
dynamic.setInitParameter( Constants.SERVLET_PARAMETER_LEGACY_DESIGN_PREFIX, Boolean.TRUE.toString() );
...
Related
With Spring's AbstractRefreshableApplicationContext, I am able to force Spring to fail if there is a conflict in Bean IDs or circular references by setting a couple of flags and refreshing the context like so:
AbstractRefreshableApplicationContext refreshableContext;
...
refreshableContext.setAllowBeanDefinitionOverriding(false);
refreshableContext.setAllowCircularReferences(false);
refreshableContext.refresh();
However, Spring Boot returns a ConfigurableApplicationContext which is not an instance of AbstractRefreshableApplicationContext and does not appear to have any means to prevent bean definition overriding or circular references.
Does anyone know of a way and have an example of how to prevent these types of conflicts?
For context, this is for a large project that has a mix of annotated and xml defined beans. The version of Spring Boot used is 1.3.1.RELEASE. There have been some cases where folks added duplicate bean definitions in the xml, but the application started up fine and wasn't immediately apparent the original bean was overridden until run-time issues started occurring.
The goal here is to prevent the application from event starting up if such a conflict occurs. From various forums I know Spring IDE can detect these, but the desire is to enforce this in the CI build which is a stronger safety net.
After some searching, I can't find any support for this in the context that Sprint Boot returns. If this can't be done through the context, is there a different solution available?
Thanks in advance.
You may use an initializer when building your Spring Boot app:
#SpringBootApplication
public class SpringBootApp {
public static void main(String... args) {
new SpringApplicationBuilder(SpringBootApp.class)
.initializers(new ApplicationContextInitializer<GenericApplicationContext>() {
#Override
public void initialize(GenericApplicationContext applicationContext) {
applicationContext.setAllowBeanDefinitionOverriding(false);
}
})
.run(args);
}
}
Or with java 8:
new SpringApplicationBuilder(SpringBootApp.class)
.initializers((GenericApplicationContext c) -> c.setAllowBeanDefinitionOverriding(false) )
.run(args);
add below into your application.yml
spring.main.allow-bean-definition-overriding: false
I have a servlet packaged in an ear file, and I cannot get it to resolve #Value annotated properties.
The app is in two parts: a servlet packaged in a war file, which is then included by different applications packaged in an ear file. The application supplies the implementation of a class (ResourceManager) defined by an interface in the servlet, and also the property file containing the value of the property for the #Value annotated field.
The war file contains:
web.xml:
<servlet>
<servlet-class>... extends MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/spring-ws.xml
classpath:/spring-app.xml
</param-value>
</init-param>
</servlet>
spring-ws.xml:
<context:annotation-config/>
<context:property-placeholder location="classpath:/spring-ws.properties"/>
The values in spring-ws.properties are referenced directly from spring-ws.xml, and all work fine.
The servlet class contains:
public class MyServlet extends MessageDispatcherServlet
#Autowired private ResourceManager resourceManager; // original annotation - got this to work
#Value("${app.name:}") private String appName; // added later - cannot get this to work
The app.name is optional, hence the trailing ":".
The ear file adds (packaged in a jar file in the ear lib directory):
spring-app.xml:
<context:property-placeholder location="classpath:/spring-app.properties"/>
<bean class="ResourceManagerImpl">
...
</bean>
spring-app.properties:
app.name=myApp
My first problem was with the #Autowired annotation: not sure I ever got to the bottom of that correctly, but I managed to get it to work by adding this code to the servlet:
#Override
protected void initFrameworkServlet() throws ServletException {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(getWebApplicationContext().getAutowireCapableBeanFactory());
bpp.processInjection(this);
}
This may not be the best way to fix this, but it was the first I found and it worked, so I used it and moved on. Then I added a #Value annotated field, and I can't find a way to make this work. The javadocs for AutowiredAnnotationBeanPostProcessor say that it should process #Value annotations as well, but it doesn't appear to: the appName property is always blank (presumably from the default).
I do have a workaround, using beans:
#Autowired #Qualifier("appName") private String appName;
<bean id="appName" class="java.lang.String">
<constructor-arg value="myApp"/>
</bean>
But I'm sure there must be a better way of doing this. I've read this post Difference between applicationContext.xml and spring-servlet.xml in Spring Framework, but I'm not sure it applies: I don't think I even have an application context here, just a servlet context defined in the web.xml for the (single) servlet class.
I've also seen this: Spring 3.0.5 doesn't evaluate #Value annotation from properties, which looks like the same problem, but the solution there appeared to be to move the "<context:property-placeholder>" from the application context to the servlet context, whereas as I said before, I don't think I even have an application context here...
Finally, I've had a quick go at simplifying the problem, removing the separate app and packaging everything in a single war, but I don't think that is the problem (although could obviously be wrong...): spring can resolve the class path for the app.xml file so it must be able to resolve the class path for the app.properties file.
Any help much appreciated, but I guess at this point it is a bit of an academic interest, as I have a workable solution (using beans) and the people that pay the bills don't really care how it works as long as it works! I'd just like to know so next time I don't have to copy (what I think is) a flawed workaround.
Using spring-ws-core 2.1.4, which pulls in spring 3.2.4 via maven dependencies.
Thanks
Update - Solved
Turns out the key to fixing this was M Deinum's comment that "You also have a duplicate element...". I had two separate PropertyPlaceholderConfigurers in the same context, so the second was ignored and its properties never used. There was no problem with the context itself (which is a servlet context not a root context), or the annotation processing.
So the fix was simply to remove the property placeholder from the spring-app.xml, and combine both property files in the spring-ws.xml
<context:property-placeholder
location="classpath:/spring-ws.properties,
classpath:/spring-app.properties"/>
TL;DR's answer here Spring: namespace vs contextConfigLocation init parameters in web.xml is also an awesome explanation of how the different contexts are processed!
Cheers,
Your servlet isn't a spring managed bean it is managed by the Servlet container. Hence the reason why #Autowired doesn't work in the first place. Spring will only process beans it knows.
Both the ContextLoaderListener and your servlet (basically any servlet that extends FrameworkServlet) have there own instance of an ApplicationContext. The one from the ContextLoaderListener is used as a parent by the context constructed in the servlet. So you indeed have an ApplicationContext in your servlet.
Now for this #Value to resolve properly you need to have a PropertyPlaceHolderConfigurer to resolve the placeholders. As PropertyPlaceHolderConfigurer is a BeanFactoryPostProcessor it only operates on beans in the same context, so the one loaded/configured by the ContextLoaderListener doesn't do anything for beans related to the context from your servlet. (Hence you need to add <context:property-placeholder ... /> element to the servlet context).
You also have a duplicate element in general you want to avoid that kind of situation as it will lead to problems at same time, either one overriding the other or you will get exceptions that placeholders cannot be resolved by either one of the PropertyPlaceHolderConfigurer
Your init code is also overly complex and you don't need the AutowiredAnnotationBeanPostProcessor simply use the available methods.
getWebApplicationContext().getAutowireCapableBeanFactory().autowireBean(this);
Which also does more then what only the AutowiredAnnotationBeanPostProcessor does.
for #Autowired annotation, you just need to have a class with those annotations:
#Configuration
#PropertySource("classpath:myFile.properties")
#ComponentScan("com.company.package")
The #Configuration is used by Spring to tell it's a class for configuration (it replaces the xml files that you talked about, xml conf file is Spring 2, annotation is new with Spring 3 and 4)
The #ComponentScan manage the IOC (#Autowire)
The #PropertySource load the prop file
Then the class to initialized at startup with the prop file:
#Component("myFileProperties")
public class MyFileProperties{
#Value("${app.name}")
private String appName;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName= appName;
}
}
Take a look here if you want it can inspire you (a conf file in a web context that I developped): https://github.com/ebrigand/RSSLiker/blob/master/src/main/java/com/mrm/rss/init/WebAppConfig.java
There is a workaround for this.
You can create a static field in a java class to store the value in.
public class SystemPropertyHelper {
public static String propertyValue;
}
And create a java class annotated with #Service or #Component, which you can inject the property in, and pass this value to the static field.
#Component
public class SpringBeanClass {
#Value("${propertyName}")
private String propertyValue;
#PostConstruct
public void init() {
SystemPropertyHelper.propertyValue = propertyValue;
}
}
This way you can always access the property value through the static field SystemPropertyHelper.propertyValue
I have a filter where I am dinamically mapping servlet classes:
#Override
public void init( FilterConfig filterConfig ) throws ServletException {
servletContext = filterConfig.getServletContext();
File directory = getConventionDirectory();
FileSystemInspector fileInspector = new FileSystemInspector();
Set<ActionInfoData> actions = fileInspector.getActions( directory );
for ( ActionInfoData action : actions ) {
servletContext
.addServlet( action.getServletName(), action.getClassName() )
.addMapping( action.getServletMapping() );
}
}
Then when I access a given mapping the EJB is not injected.
#EJB
private I18nManager i18nManager;
#Override
protected void doGet( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException {
I18nManager i18n = i18nManager; //null
}
If I manually create a mapping in the web.xml the given EJB is working in that servlet.
It makes me wonder if the fact I am registering the servlets at runtime the container does not consider those servlets as managed.
If that is the case what is the proper way to inject the EJBs into my servlets without changing the way they are dinamically registered via filter?
Is via JNDI the only way to inject my EJBs?
EDIT 1:
I have tried to implement a ServletContextListener class as suggested by "Will" using the following code in the web.xml:
<listener>
<listener-class>com.megafone.web.filter.convention.InitServlet</listener-class>
</listener>
And the relevant part of the implementation:
...
#Override
public void contextInitialized( ServletContextEvent sce ) {
ServletContext servletContext = sce.getServletContext();
FileSystemInspector fileInspector = new FileSystemInspector();
Set<ActionInfoData> actions = fileInspector.getActions( getConventionDirectory() );
for ( ActionInfoData action : actions ) {
servletContext
.addServlet( action.getServletName(), action.getClassName() )
.addMapping( action.getServletMapping() );
}
}
...
Unfortunately it does not make the container inject the EJBs and the null pointer remains. I am currently making a custom type safe JNDI lookup to the service. Obviously this is far more expensive than using the proper injection (correct me if I am wrong, have done no experiments regarding performance yet).
Using:
Java EE 6
JBoss AS 7.1
The problem seems related to this reported bug which is as yet unresolved. Resource resolution works just fine for Managed Beans as defined by the JSF specification, but not for CDI Managed Beans. Simply annotating your dynamic servlet classes with #javax.faces.bean.ManagedBean should fix the problem (yes, its quite an ugly solution):
#ManagedBean
public class DynServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private LoginService loginService;
public DynServlet() {
super();
}
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getOutputStream().println(
"Request made to: " + getClass().getSimpleName());
response.getOutputStream().println("Login Service: " + loginService);
return;
}
}
#WebListener
public class DynamicServletLoadListener implements ServletContextListener {
public DynamicServletLoadListener() {
super();
}
#Override
public void contextDestroyed(final ServletContextEvent contextEvent) {
return;
}
#Override
public void contextInitialized(final ServletContextEvent contextEvent) {
contextEvent.getServletContext().addServlet("dynservlet", DynServlet.class)
.addMapping("/services/dynservlet");
}
}
Tested with JEE6 (ofc) and both JBoss 7.1.1 and 7.2.0 (EAP 6.1.0 Alpha).
Edit:
The problem with dynamic mapped servlets is actually pretty deep in the base JBoss architecture. They use JBossWeb (a forked version of Tomcat) as the servlet implementation, and in the guts of its context management code it makes a determination wether to instantiate new components via injection or regular new. Afaik as of date, your servlets would need to be annotated in some fashion in order for them to be processed via injection: I had mentioned #ManagedBean in my original answer but it looks like annotating with #WebServlet works as well.
Servlet 3.0 Spec, Sect. 4.4.3.5
Resource injection [e.g. #EJB] on all components (Servlets, Filters and Listeners) added
programmatically or created programmatically, other than the ones added via the
methods that takes an instance, will only be supported when the component is a
Managed Bean. For details about what is a Managed Bean please refer to the
Managed Bean specification defined as part of Java EE 6 and JSR 299.
Managed Bean Declaration
A Java EE 6 managed bean is annotated #javax.annotation.ManagedBean and has a no-arg constructor. A JSR 299 (CDI) managed bean merely needs a no-arg constructor or a constructor annotated #javax.inject.Inject.
Answer
To enable resource injection you need to:
place #ManagedBean annotation on dynamically added servlet
OR
enable CDI & include an empty beans.xml
Edit
Even though you're creating the servlet dynamically, it's important that the container does the creation. Don't think creation within ServletContext will support injection. Servlet doc very vague here.
With CDI try:
servletContext.addServlet("your servlet name", #Inject YourServletClass servlet)
First, in my test, this worked fine using a version of Glassfish V3.
But, second, you may well be running afoul of this clause of the Servlet 3.0 spec.
The following methods are added to ServletContext since Servlet 3.0 to
enable programmatic definition of servlets, filters and the url
pattern that they map to. These methods can only be called during the
initialization of the application either from the contexInitialized
method of a ServletContextListener implementation or from the
onStartup method of a ServletContainerInitializer implementation.
Notably, these methods can NOT be called from a Filter.init() method. I originally tried this in a Servlet.init() method, and the init method failed because the context was already initialized.
So, my experiment did not duplicate your test exactly -- I did not use a Filter.init() method for this, rather I put the code in a ServletContextListener. And when I did that, my #EJB annotation was honored.
Edit:
As un-helpful as it sounds, I would suggest this is a bug in JBoss. When I initially tried your original code with the injection from the Filter, Glassfish threw an exception, since you're not allowed to do the injection save where I mentioned earlier. Now perhaps that's an "added feature" of JBoss, but apparently the #EJB injection processing simply isn't working. According to spec, this should work as advertised.
I am using Spring framework (2.5.4) in my app with Load time weaving and everything works fine everywhere (in Spring beans, in non-Spring entities), except when I try to autowire field in a servlet annotated as #Configurable, then I get a nice NullPointerException...
#Configurable(dependencyCheck=true)
public class CaptchaServlet extends HttpServlet{
#Autowired
private CaptchaServiceIface captchaService;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
// ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
// captchaService = (CaptchaServiceIface) ctx.getBean("captchaService");
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Captcha c = captchaService.getCatpcha();
req.getSession().setAttribute("captchaAnswer", c.getAnswer());
resp.setContentType("image/png");
ImageIO.write(c.getImage(), "png", resp.getOutputStream());
}
}
<context:load-time-weaver/>
<context:spring-configured/>
<context:component-scan base-package="cz.flexibla2" />
Any suggestions about what am I doing incorrectly?
Thanks.
This is likely because the Servlet is being instantiated and initialized by the servlet container, before the Spring context is being initialized, and it's the Spring context which handles the load-time weaving.
Is your <context:load-time-weaver/> stuff being handle inside the servlet Spring context/ or at the webapp-level? The former almost certainly won't work (for the reasons specified above), but a webapp-level config might work (using ContextLoaderListener).
See also mailing list discussion and bug report at https:// bugs.eclipse.org/bugs/show_bug.cgi?id=317874 . I agree that intuitively the #Configurable annotation on the servlet should be enough to indicate to the spring framework that the servlet when instantiated will be configured by spring, when using <context:spring-configured/>. I have also observed that the desired behavior is achievable when using the -javaagent:/path/to/aspectjweaver.jar instead of spring-instrument*.jar or spring-agent.jar. Please raise an issue with Spring Jira at https:// jira.springframework.org/browse/SPR. I believe that the problem may be that the servlet class - not an instance of the servlet, but the class itself - is loaded before the spring ContextLoaderListener is called, thus the spring framework does not have a chance to instrument the servlet class before it is loaded.
The spring instrumentation for load-time-weaving appears to be based on being able to transform class bytecode before it is loaded. If the servlet container is holding onto an instance of the Class object that was obtained before it was transformed by spring, then it (the servlet container) would not be able to produce instances of the transformed class, nor would spring be able to instrument instances created using the factory methods on that Class object.
I have a bunch of java custom tags that use spring managed beans.. since i cant find a way to inject into a custom tag, i created a helper class that provides static methods to "getTheObjectINeedBean()" for all the spring bean objects i need.. I do not like this approach at all.
i really want to be able to inject a spring managed bean into the custom tag
Is there a way? As far as my research goes, I understand there is no way to do this, because the custom tag is container managed
Thanks,
Billy
You are correct there isn't a simple way to use dependency-injection in jstl tags, because they are not managed by spring, and cannot be. However there are (at least) two workarounds:
#Configurable - aspectJ allows you to plug a weaver at load-time/compile-time, so that even objects that are not instantiated by spring can be spring aware. See here
You can create a base tag class for your project, and call an init(..) method from every doStartTag(..) method. There, you can get the ServletContext from the pageContext, and thus obtain the spring ApplicationContext (via ApplicationContextUtils). Then:
AutowireCapableBeanFactory factory = appCtx.getAutowireCapableBeanFactory();
factory.autowireBean(this);
Neither options are perfect as they require either some additional code, or some "black magic"
To expand on #Bozho's post, I have gotten this to work like so: (in spring 3.0 there is no ApplicationContextUtils that I could find)
public class LocationTag extends RequestContextAwareTag {
#Autowired
PathComponent path;
...
#Override
protected int doStartTagInternal() throws Exception {
if (path == null) {
log.debug("Autowiring the bean");
WebApplicationContext wac = getRequestContext().getWebApplicationContext();
AutowireCapableBeanFactory acbf = wac.getAutowireCapableBeanFactory();
acbf.autowireBean(this);
}
return SKIP_BODY;
}
}
The solution as described above works but some background and additional code snippets are, quite likely, useful.
1) The doStartTagInternal method is invoked from the doStartTag method.
2) I was forced to set the pageContext first before invoking the doStartTag
3) I did a lookup of the bean as opposed to the autowiring. To me this seems more straightforward: (YourBeanProxy) autowireCapableBeanFactory.getBean("yourBeanName")
Hopefully this additional info is useful.