Skip to content
This repository was archived by the owner on Dec 15, 2018. It is now read-only.

Commit 83566ee

Browse files
mscharhagchkal
authored andcommitted
Verify that controllers are CDI beans without @nAmed (#161, #177)
1 parent 20c5424 commit 83566ee

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright © 2017 Ivar Grimstad ([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mvcspec.ozark.servlet;
17+
18+
import javax.enterprise.inject.spi.Bean;
19+
import javax.enterprise.inject.spi.BeanManager;
20+
import javax.inject.Inject;
21+
import javax.inject.Named;
22+
import javax.servlet.ServletContext;
23+
import javax.servlet.ServletContextEvent;
24+
import javax.servlet.ServletContextListener;
25+
import javax.servlet.annotation.WebListener;
26+
27+
import java.util.Set;
28+
import java.util.logging.Logger;
29+
30+
import static org.mvcspec.ozark.servlet.OzarkContainerInitializer.CONTROLLER_CLASSES;
31+
32+
/**
33+
* Performs some sanity checks for controllers during startup
34+
*/
35+
@WebListener
36+
public class OzarkServletContextListener implements ServletContextListener {
37+
38+
private static final Logger log = Logger.getLogger(OzarkServletContextListener.class.getName());
39+
40+
private BeanManager beanManager;
41+
42+
@Inject
43+
public OzarkServletContextListener(BeanManager beanManager) {
44+
this.beanManager = beanManager;
45+
}
46+
47+
@Override
48+
public void contextInitialized(ServletContextEvent sce) {
49+
50+
ServletContext servletContext = sce.getServletContext();
51+
Set<Class<?>> controllerClasses = (Set<Class<?>>) servletContext.getAttribute(CONTROLLER_CLASSES);
52+
53+
if (controllerClasses == null || controllerClasses.isEmpty()) {
54+
return;
55+
}
56+
57+
for (Class<?> controllerClass : controllerClasses) {
58+
failIfNoCdiBean(controllerClass);
59+
warnIfAnnotatedWithNamed(controllerClass);
60+
}
61+
}
62+
63+
/**
64+
* Throws an exception if the passed controller class is not present in the CDI BeanManager.
65+
* For example, this can happen with glassfish / Jersey if the application is using CDI discovery mode "annotated"
66+
* and the controller class is not annotated with any scope annotation.
67+
* Unlike in JAX-RS resources, MVC controllers are required to be CDI-managed beans.
68+
*/
69+
private void failIfNoCdiBean(Class<?> controllerClass) {
70+
Set<Bean<?>> controllerBeans = beanManager.getBeans(controllerClass);
71+
if (controllerBeans == null || controllerBeans.isEmpty()) {
72+
String message = String.format("The controller %s is not a managed CDI bean. Maybe the controller class is " +
73+
"missing a scope annotation (e.g. @RequestScoped).", controllerClass.getName());
74+
throw new IllegalArgumentException(message);
75+
}
76+
}
77+
78+
/**
79+
* Logs a warning if the passed controller class is annotated with {@link Named}.
80+
*/
81+
private void warnIfAnnotatedWithNamed(Class<?> controllerClass) {
82+
Named namedAnnotation = controllerClass.getAnnotation(Named.class);
83+
if (namedAnnotation != null) {
84+
String message = String.format("Controller class %s is annotated with @Named. Typically this should not be " +
85+
"required, because you should never access the controller directly from a view.", controllerClass.getName());
86+
log.warning(message);
87+
}
88+
}
89+
90+
}
91+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright © 2017 Ivar Grimstad ([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mvcspec.ozark.servlet;
17+
18+
import org.easymock.EasyMock;
19+
import org.junit.Test;
20+
21+
import javax.enterprise.inject.spi.BeanManager;
22+
import javax.servlet.ServletContext;
23+
import javax.servlet.ServletContextEvent;
24+
import java.util.HashSet;
25+
import java.util.Set;
26+
27+
import static java.util.Collections.singletonList;
28+
import static org.easymock.EasyMock.createMock;
29+
import static org.easymock.EasyMock.expect;
30+
31+
public class OzarkServletContextListenerTest {
32+
33+
private static class TestController { }
34+
35+
36+
@Test(expected = IllegalArgumentException.class)
37+
public void failIfControllerIsNoCdiBean() {
38+
39+
BeanManager beanManager = createMock(BeanManager.class);
40+
ServletContextEvent event = createMock(ServletContextEvent.class);
41+
ServletContext context = createMock(ServletContext.class);
42+
43+
OzarkServletContextListener listener = new OzarkServletContextListener(beanManager);
44+
Set<Class<?>> controllers = new HashSet<>(singletonList(TestController.class));
45+
46+
expect(event.getServletContext()).andStubReturn(context);
47+
expect(context.getAttribute(OzarkContainerInitializer.CONTROLLER_CLASSES)).andStubReturn(controllers);
48+
expect(beanManager.getBeans(TestController.class)).andStubReturn(new HashSet<>());
49+
50+
EasyMock.replay(event, context, beanManager);
51+
52+
listener.contextInitialized(event);
53+
}
54+
55+
}

0 commit comments

Comments
 (0)