I'm trying to implement an application with several uis - vaadin, jsp and etc.
It was working with simple jsp but then I decided to use vaadin as ui.
I've created vaadin servlet(and spring servlet left too).
My web.xml looks like this
<?xml version="1.0"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/pmc-web-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>another-pmc-servlet</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UI</param-name>
<param-value>com.xxxx.app.pmc.vaadin.PmcUi</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>pmc-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>another-pmc-servlet</servlet-name>
<url-pattern>/VAADIN/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>pmc-servlet</servlet-name>
<url-pattern>/JSP/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>/WEB-INF/jsp/*</url-pattern>
</servlet-mapping>
</web-app>
I've created vaadin table component and adjusted it for my needs. I used autowiring for service.
package com.xxxx.app.pmc.vaadin.components;
import com.xxxx.app.pmc.model.Project;
import com.xxxx.app.pmc.service.project.ProjectService;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.Table;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
#Component("projectTable")
public class ProjectTable extends Table {
private static final String CAPTION = "Projects";
private static final String[] headers = { "Project name", "Project owner", "ID" };
#Autowired
private ProjectService projectService;
public Table createTable() {
this.setContainerDataSource(projectDatasource());
this.setVisibleColumns(headers);
this.setSelectable(true);
this.setImmediate(true);
return this;
}
public IndexedContainer projectDatasource() {
IndexedContainer indexedContainer = new IndexedContainer();
for(String header: headers) {
indexedContainer.addContainerProperty(header, String.class, "");
}
List<Project> projects = projectService.findAllProjects();
for(int i = 0; i < projects.size(); i++) {
Object id = indexedContainer.addItem();
Project item = projects.get(i);
indexedContainer.getContainerProperty(id, headers[0]).setValue(item.getProjectName());
indexedContainer.getContainerProperty(id, headers[1]).setValue(item.getProjectOwner());
indexedContainer.getContainerProperty(id, headers[1]).setValue(item.getProjectId());
}
return indexedContainer;
}
}
ProjectService is a spring bean too.
#Service("projectService")
public class ProjectService {
#Autowired
private ProjectRepository projectRepository;
public void insertProject(Project project) {
projectRepository.store(project);
}
public List<Project> findAllProjects() {
return projectRepository.getAllItems();
}
public Project getProject(String id) {
return projectRepository.get(id);
}
}
ProjectRepository is another spring bean. It uses SqlSessionTemplate bean from MyBatis.
#Repository("projectRepository")
public class ProjectRepository implements IRepository<Project> {
private static final String STORE_PROJECT = "Project.insertProject";
private static final String GET_PROJECT_BY_ID = "Project.getProjectById";
private static final String GET_PROJECT_LIST = "Project.getProjectList";
#Autowired
private SqlSessionTemplate sqlSessionTemplate;
#Override
public void store(Project object) {
sqlSessionTemplate.insert(STORE_PROJECT, object);
}
#Override
public Project get(String id) {
return sqlSessionTemplate.selectOne(GET_PROJECT_BY_ID, id);
}
#Override
public List<Project> getAllItems() {
return sqlSessionTemplate.selectList(GET_PROJECT_LIST);
}
}
When I wrote an application using spring controller(using JSP) - it was working fine.
But when I added vaadin - JSP stopped working and vaadin application throws NullPointerException for ProjectService, ProjectRepository... all the beans I use.
What is the problem?
All my context xml context files are simple.
<import resource="classpath:com/xxxx/app/pmc/pmc-service-context.xml"/>
<context:component-scan base-package="com.xxx.app.pmc"/>
And my pmc-web-context.xml has this lines too.
<mvc:annotation-driven/>
<context:annotation-config/>
It was working fine with JSP so I think the problem is not with spring declarations itself but with integration of spring into vaadin of mine.
How to resolve it?
When I for example created ProjectTable object manually - it throws NullPointerException for ProjectService. When I create ProjectService manually - it throws NullPointerException for ProjectRepository and so on. It seems autowiring simply doesn't work.
P.S forgot to add my UI code
package com.xxxx.app.pmc.vaadin;
import com.xxxx.app.pmc.vaadin.components.ProjectTable;
import com.vaadin.annotations.Title;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import org.springframework.stereotype.Component;
#Title("PMC")
#Component("pmcVaadin")
public class PmcUi extends UI {
#Override
protected void init(VaadinRequest request) {
VerticalLayout mainLayout = new VerticalLayout();
ProjectTable projectTable = new ProjectTable();
mainLayout.addComponent(projectTable.createTable());
mainLayout.setSizeFull();
setContent(mainLayout);
}
}
Like you suspected your Spring beans are created, but in application and Spring's servlet contexts. Your Vaadin servlet has no access to any of those.
For detailed (manual) solution with code either check Vaadin's wiki or search for a proper Vaadin's add ons that will do the job for you (personally I recommend SpringVaadinIntegration).
The typical idea is to programmatically pass Vaadin servlet to one of Spring's utility classes (eg.: WebApplicationContextUtils) and retrieve application context (loaded by ContextLoaderListener). If you need servlet context, then from code examples I have seen, you do the same as above, but additionally manually read context (eg.: using XmlWebApplicationContext) and set application context as it's parent.
Pretty easy option is to use Configurable support. It'll do some aspect magic and all java objects annotated by #Configurable will be automatically integrated into Spring. You can find more details in Spring documentation. Also please note that to represent context information in GUI you will have to use session beans. That causes the problem with session size, and in bigger applications makes it impossible to cluster.
Related
How can I make my Spring Rest HelloWorld app work without using Spring Boot?
When running this project in tomcat 8.5 within eclipse, I expect the url "localhost:8080/hello" to show "HelloWorld", but instead it shows 404
src/main/java/com.package/HelloController.java
#RestController
public class HelloController {
#RequestMapping("/hello")
public String helloWorld() {
return "Hello World";
}
}
src/main/java/com.package/HelloConfig.java
public class HelloConfig {
#Bean
public HelloController helloController() {
return new HelloController();
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(HelloConfig.class);
context.getBean(HelloController.class);
}
}
build.gradle
plugins {
id 'java'
id 'war'
id 'eclipse-wtp'
}
dependencies {
compile 'org.springframework:spring-context:5.0.3.RELEASE'
compile 'org.springframework:spring-web:5.0.3.RELEASE'
testCompile 'junit:junit:4.12'
}
repositories {
mavenCentral()
}
Answering my own question: the missing bit was the DispatcherServlet, the logic responsible for delegating http requests to Controllers, like HelloController in my example.
Based on Spring docs (https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet), there are 3 ways to configure DispatcherServlet:
in web.xml
overriding WebApplicationInitializer
extending AbstractAnnotationConfigDispatcherServletInitializer (recommended for apps with Java based configurations like mine)
src/main/java/com.package/ServletInitializer:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { HelloConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
note: why the downvotes?
You may need to WebApplicationInitializer and AnnotationConfigWebApplicationContext on start up.In onStartup Method you can mention the root context of your application and access the controller mapping thereon.
public class CustomWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfiguration.class);
ContextLoaderListener contextLoaderListener = new ContextLoaderListener(rootContext);
container.addListener(contextLoaderListener);
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.register(MvcConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", dispatcherServlet);
dispatcher.addMapping("/");
}
}
I am not sure if you have checked your web.xml for web application and you have correctly set the below configuration
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:pathToYourSpringBeanConfig/channel-application-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath: pathToYourSpringBeanConfig/channel-application-context.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Also you need to provide location of your context xml application where you need to tell your context like following details:
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="group.*"></context:component-scan>
PS : if you want to access URL without war name you might wanna check this
Deploy war on Tomcat without the war name in the URL
I am learning Spring and i created the following interfaces and classes all under the same package
public interface CompactDisc {
public void play();
}
-
#Component
public class StgPeppers implements CompactDisc{
private String title = "Stg. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
#Override
public void play(){
System.out.println("Playing "+title+" by "+artist);
}
}
-
#Configuration
#ComponentScan
public class CDPlayerConfig {
}
That are tested using
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
#Autowired
private CompactDisc cd;
#Test
public void cdShouldNotBeNull() {
Assert.assertNotNull(cd);
}
}
I am following these examples from a book, it asks to test that it's working but not how to do that so i created under the same package a main class that just does that
public class Main {
public static void main(String[] args){
new CDPlayerTest().cdShouldNotBeNull();
}
}
In the console i have
Exception in thread "main" junit.framework.AssertionFailedError
at junit.framework.Assert.fail(Assert.java:55)
at junit.framework.Assert.assertTrue(Assert.java:22)
at junit.framework.Assert.assertNotNull(Assert.java:256)
at junit.framework.Assert.assertNotNull(Assert.java:248)
at automaticWiring.CDPlayerTest.cdShouldNotBeNull(CDPlayerTest.java:30)
at automaticWiring.Main.main(Main.java:17)
All the imports of the classes are correct even if omitted, i am using a Netbeans webapp with Spring Web MVC framework, i also had to add JUnit 4.12 jar to the library since it wasn't there at the beginning.
Is there something wrong with the Spring code or is my testing method incorrect ?
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>redirect.jsp</welcome-file>
</welcome-file-list>
</web-app>
You could try this :
#RunWith(SpringRunner.class)
#SpringBootTest
public class CDPlayerTest {
#Autowired
private CompactDisc cd;
...
}
Keep in mind that the test-class loads the entire application context whene before executing the tests.
I am pretty new to spring. I have dynamic web application project. Inside i have a servlet which is receive request. The request comes with a request no. Based on the no i will create a new object for appropriate request class and serve the request. Now i need to integrate with spring. i applied the below configuration,
WEB.XML (To load spring context)
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/docspring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
In servlet
package com.receve;
#Controller
#WebServlet("/Recever")
public class Recever extends HttpServlet {
#Autowired
private ClassOne one;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//request parameters receved and
if(req==1){
one.print();
}
}
public ClassOne getOne() {
return One;
}
public void setOne(ClassOne one) {
this.one = one;
}
}
In ClassOne
package com.operations;
#Component
public Class ClassOne{
public void print(){
//some statement;
}
}
In spring.xml
<context:annotation-config />
<context:component-scan base-package="com" />
But while running the application i am getting NullPointerexception while calling one.print() method. what is the proper way(configuration) to obtain this?
Thanks.
Remove extends HttpServlet and Autowiring is turned off by default, so the default autowiring mode for a bean is 'no'.
I have what I think is a very basic question about JAX-RS but I somehow can't easily find the answer.
I am trying to refactor a REST service which uses a "standard" Javax servlet -- routing requests to methods by hand -- into an "cleaner" JAX-RS implementation. The current application sets some variables during the servlet init(). It assigns those as attributes of the HttpServlet class so they are available during each doGet() and can be passed as parameters to request processing methods. For clarity, one of these is a ConcurentHashMap that acts as a cache.
Now, with JAX-RS, I can extend Application to set my resource classes. I can also use the #Context annotation in each resource implementation to inject things like ServletContext when processing a request. But I do not know how to similarly inject variables set during application initialization.
I am using the Apache Wink 1.3.0 implementation of JAX-RS.
You can use a listener for init the cache and set to the context as attribute before the web application start. something like the following:
package org.paulvargas.shared;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class CacheListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
Map<String, String> dummyCache = new HashMap<String, String>();
dummyCache.put("greeting", "Hello Word!");
ServletContext context = sce.getServletContext();
context.setAttribute("dummyCache", dummyCache);
}
public void contextDestroyed(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
context.removeAttribute("dummyCache");
}
}
This listener is configured in the web.xml.
<listener>
<listener-class>org.paulvargas.shared.CacheListener</listener-class>
</listener>
<servlet>
<servlet-name>restSdkService</servlet-name>
<servlet-class>
org.apache.wink.server.internal.servlet.RestServlet
</servlet-class>
<init-param>
<param-name>applicationConfigLocation</param-name>
<param-value>/WEB-INF/application</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>restSdkService</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
You can use the #Context annotation for inject the ServletContext and retrieving the attribute.
package org.apache.wink.example.helloworld;
import java.util.*;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.apache.wink.common.model.synd.*;
#Path("/world")
public class HelloWorld {
#Context
private ServletContext context;
public static final String ID = "helloworld:1";
#GET
#Produces(MediaType.APPLICATION_ATOM_XML)
public SyndEntry getGreeting() {
Map<String, String> dummyCache =
(Map<String, String>) context.getAttribute("dummyCache");
String text = dummyCache.get("greeting");
SyndEntry synd = new SyndEntry(new SyndText(text), ID, new Date());
return synd;
}
}
I am having some difficulty auto-wiring beans into a class which is loaded as an init-param in a servlet for OData4j. I have tried many solutions including load-time-weaving but cannot seem to get it to work correctly because as I understand it, the class which is being passed as an init-param to the servlet is being loaded prior to Spring context being loaded at all. Below is the current state of my configuration, is there a way to have dependency injection in a class loaded in such a way? The end goal is to have the ExampleProducerFactory.java (which is an init-param of the OData servlet) having the UserDao bean autowired.
I have tried to just include the key pieces of each of these files, if there is additional configuration information needed, please comment.
applicationContext.xml
<context:component-scan base-package="com.project.core"/>
<context:spring-configured/>
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" />
web.xml
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<!-- read the XmlWebApplicationContext for spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>OData</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>org.odata4j.producer.resources.ODataResourceConfig</param-value>
</init-param>
<init-param>
<param-name>odata4j.producerfactory</param-name>
<param-value>com.wildgigs.core.odata.ExampleProducerFactory</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>OData</servlet-name>
<url-pattern>/example.svc/*</url-pattern>
</servlet-mapping>
ExampleProducerFactory.java
#Configurable(autowire= Autowire.BY_NAME)
public class ExampleProducerFactory implements ODataProducerFactory {
#Autowired
private UserDao userDao;
#Override
public ODataProducer create(Properties arg0) {
InMemoryProducer producer = new InMemoryProducer("example");
List<User> users = userDao.findAll();
User[] usersArray = new User[users.size()];
users.toArray(usersArray);
final User[] usersArrayFinal = usersArray;
producer.register(User.class, Long.class, "Users", new Func<Iterable<User>>() {
public Iterable<User> apply() {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
while (tg.getParent() != null)
tg = tg.getParent();
return Enumerable.create(usersArrayFinal).take(usersArrayFinal.length);
}
}, "Id");
return producer;
}
}
UserDaoImpl.java
#Repository
public class UserDaoImpl extends GenericDaoImpl<User, Long> implements UserDao, Serializable {
#Transactional(readOnly = true)
public User getByUserName(String userName) {
Query query = getSession().createQuery("FROM User where upper(userName) = :name");
query.setString("name", userName.toUpperCase());
return (User) query.uniqueResult();
}
}
You should use the jersey SpringServlet instead of the ServletContrainer. With that instead of specifying resourceConfig in the init param you can define it as a spring bean.
A bean must be created in your spring config to inject into your class.
<bean id="userDao" class="com.yourdomain.pacakage.UserDao">