I have a problem with REST web service running with Spring Boot (Jetty).
One of my REST method is file upload and I'm guessing that CommonsMultipartResolver is not using during multipart requests.
Signature of this upload method is :
#ResponseBody
#RequestMapping(value = "/upload", method = RequestMethod.POST, produces = "application/json")
public BaseResponse upload(#RequestParam("login") String login, #RequestParam("passwd") String passwd,
#RequestParam("partner") String partner, #RequestParam("fileName") String fName,
#RequestParam("length") int fLen, #RequestParam("file") MultipartFile file) throws IOException
I also have a root application class like below :
#SpringBootApplication
public class BootApplication {
private static final Logger _logger = Logger.getLogger(BootApplication.class.getName());
public static void main(String[] args) {
SpringApplication app = new SpringApplication(BootApplication.class,
new ClassPathResource("WEB-INF/applicationContext.xml"),
new ClassPathResource("WEB-INF/dispatcher-servlet.xml"));
app.run(args);
}
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver(ServletContext servletContext) {
_logger.log(Level.INFO, "[BootApplication] Fetching CommonsMultipartResolver");
return new CommonsMultipartResolver(servletContext);
}
}
When I'm calling this method I got an error :
org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:253)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:94)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:808)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:224)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:295)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:68)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
What's strange in this stack trace I cannot see any CommonsMultipartResolver calls.
Another thing is that exactly the same code was working in GlassFish environment - I could upload files with no problem. What changed is that multipartResolver bean in GlassFish was defined in dispatcher-servlet.xml and in Spring Boot I initialize it in BootApplication class. I also tried to left multipartResolver in dispatcher-servlet.xml which I'm also loading for configuration but none of this solution worked.
When I'm looking at /beans endpoint in Spring Boot I can see multipartResolver bean. No other bean has dependency to this multipartResolver bean - maybe this is wrong, but I have no idea how to configure it properly.
Below you have my dispatcher-servlet.xml if it will help :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.my.package" />
<mvc:annotation-driven />
</beans>
You are using Spring Boot then use it, you are trying to work around it.
Spring Boot by default already configures file uploading so you can remove your definition. If you want to control certain values you can configure those by adding properties to the application.properties. See this section of the reference guide.
I would suggest removing your dispatcher-servlet.xml because Spring Boot already enables MVC configuration and you enabling it interferes with the auto configuration. Assuming that your BootApplication is inside the com.my.package you can already remove the file as it adds nothing, if the BootApplication is in a different package add #ComponentScan("com.my.package") to the configuration.
To import the applicationContext.xml add a #ImportResource to your BootApplication instead of what you are doing now. However depending on what is in there (probably some datasource, JPA, etc. configuration you might even remove it and replace it with some simple properties instead).
#SpringBootApplication
#ComponentScan("com.my.package")
#ImportResource("WEB-INF/applicationContext.xml")
public class BootApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(BootApplication.class, args);
}
}
The main problem is is that you are disabling part of the Spring Boot auto configuration to properly let it configure things.
I think they have resolved the issue in Spring-Boot 1.4.2.RELEASE
#Bean
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver multipart = new CommonsMultipartResolver();
multipart.setMaxUploadSize(3 * 1024 * 1024);
return multipart;
}
#Bean
#Order(0)
public MultipartFilter multipartFilter() {
MultipartFilter multipartFilter = new MultipartFilter();
multipartFilter.setMultipartResolverBeanName("multipartResolver");
return multipartFilter;
}
You also need to exclude Spring-Boot's MulipartAutoConfiguration.class
#EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})
This worked for me.
Related
Dears,
I have created a junit5 test case ( UserDaoTests.java) but I am not able to get DataSource Bean defined in the spring configuration file (data.xml).
Project Structure:
test cases are defined in test/com/caveofprogramming/spring/test/tests package, UserDaoTests.java class.
data.xml
configuration file for junit. I have defined datasource bean in it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan
base-package="com.caveofprogramming.spring.test.tests">
</context:component-scan>
<context:annotation-config></context:annotation-config>
<mvc:annotation-driven></mvc:annotation-driven>
<context:property-placeholder
location="test/com/caveofprogramming/spring/test/config/jdbc.properties" />
<beans profile="dev">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="username" value="${jdbc.username}"></property>
</bean>
</beans>
</beans>
jdbc.properties:
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:#(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = TESTD01)))
jdbc.password=1234
jdbc.username=offerTest
Junit test(UserDaoTests.java)
package com.caveofprogramming.spring.test.tests;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import com.offers.DAO.UserDAO;
#ActiveProfiles("dev")
#ContextConfiguration(locations = {
"classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
public class UserDaoTests {
#Autowired
private UserDAO userDao;
private static DataSource dataSource;
private JdbcTemplate jdbc;
#Autowired
public UserDaoTests() {
ApplicationContext context = new FileSystemXmlApplicationContext("test/com/caveofprogramming/spring/test/config/data.xml");
this.dataSource = (DataSource) context.getBean("dataSource");
}
#Test
public void testCreateUser() {
if ( dataSource == null) {
System.out.println("DataSource is null");
}
else {
System.out.println("DataSource is not null!!!! ");
}
}
}
Logs:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'dataSource' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:816)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1288)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
I would also like to clarify that I am using static DataSource because I need to use #BeforeAll, which require static fields only.
I have tested for non static Data Source as well but result is still the same.
--Update----
I removed <beans profile="dev"> tag from data.xml config file and it's working fine. But I don't understand why it's not working with profile.
--- Update 2 ( Update on on Bhushan's answer) -----
UserDaoTests - updated code
#ExtendWith(SpringExtension.class)
//Add all required depency xml
#ContextConfiguration(locations = { "classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
#ActiveProfiles("dev")
public class UserDaoTests {
#Autowired
private UserDAO userDao;
#Autowired
private DataSource dataSource;
#Autowired
private JdbcTemplate jdbc;
#Test
public void testCreateUser() {
Assertions.assertNotNull(dataSource);
// Assertions.assertNotNull(jdbc);
}
}
Error Stacktrace:
org.opentest4j.AssertionFailedError: expected: not <null>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:39)
at org.junit.jupiter.api.Assertions.fail(Assertions.java:109)
at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:47)
at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:36)
at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:31)
at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:283)
at com.caveofprogramming.spring.test.tests.UserDaoTests.testCreateUser(UserDaoTests.java:38)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:43)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:82)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:73)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:141)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Here you are creating multipe application context, one is creating with #ContextConfiguration and another one with FileSystemXmlApplicationContext, so avoid FileSystemXmlApplicationContext and update your code following
#ExtendWith(SpringExtension.class)
//Add all required depency xml
#ContextConfiguration(locations = {
"classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
#ActiveProfiles("dev")
public class UserDaoTests {
#Autowired
private UserDAO userDao;
#Autowired
private DataSource dataSource;
#Autowired
private JdbcTemplate jdbc;
#Test
public void testCreateUser() {
Assertions.assertNotNull(dataSource);
Assertions.assertNotNull(jdbc);
}
}
Also avoid #BeforeAll as its coupled with static memory, and ours Beans are managed by spring so can't go with it, instead of it you can you for #BeforeEach and if you want perform some logic witch you want run only once for all test cases so you can do hack something like
private AtomicBoolean executed = new AtomicBoolean(false);
#BeforeEach
public void runOnce() {
if(!executed.getAndSet(true)) {
// write you logic which you want will run only once for all test cases
}
}
I created a sample IntegrationFlow as shown below:
#Configuration
#EnableIntegration
#IntegrationComponentScan
#ComponentScan
public class RegisterHostFlow {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
#MessagingGateway
public interface RegisterHostGateway{
#Gateway(requestChannel = "registerHostInputChannel")
Host registerHost(Host host);
}
#Bean
public IntegrationFlow httpInboundGatewayFlow() {
return IntegrationFlows.from("registerHostInputChannel")
.handle((host, headers) -> {
return host;
})
.enrich(e -> e
.requestPayload(Message::getPayload)
.property("uuid", "34563456345634563456")
.property("id", "1234")
)
.get();
}
}
I am calling this from a spring MVC controller as below:
RegisterHostFlow.RegisterHostGateway registerHostGateway = applicationContext.getBean(RegisterHostFlow.RegisterHostGateway.class);
Host host1 = registerHostGateway.registerHost(host);
When I write a unit test to do some sanity testing as shown below, application fails to load with the error, NoSuchBeanException:
#RunWith(SpringRunner.class)
#WebMvcTest(HostController.class)
#EnableIntegration
#IntegrationComponentScan
public class HostControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void registerHost_passedInHost_returnJson() throws Exception {
this.mvc.perform(post("/hostservice/v1/hosts").contentType(MediaType.APPLICATION_JSON). content('someJsonStringGoesHere'))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
}
Below is the exception I see:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'registerHostInputChannel' available
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155)
Any pointers to how to have ApplicationContext autowire the integration beans when in test mode?
According the #WebMvcTest JavaDocs:
* Typically {#code #WebMvcTest} is used in combination with {#link MockBean #MockBean} or
* {#link Import #Import} to create any collaborators required by your {#code #Controller}
* beans.
You have to make your test class config like:
#RunWith(SpringRunner.class)
#WebMvcTest(HostController.class)
#Import(RegisterHostFlow.class)
public class HostControllerTest {
So, this way you have an MVC slice and collaborator in face of Spring Integration and target flow configuration.
I am using Springs framework 3.2.0. and i am not able to use #component annotation. Below is the error which i received when Test.java was executed.
I tried changing the java version, and springs framework version but nothing worked.
Beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="util-namespace"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.ds.cab.car" />
<bean id="e" class="com.ds.cab.engine.Engine">
<property name="modelyear" value="2015 AUDI"></property>
</bean>
</beans>
Car.java
package com.ds.cab.car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ds.cab.engine.Engine;
#Component
public class Car {
#Autowired
private Engine engine;
public void setEngine(Engine engine) {
this.engine = engine;
}
public void printData() {
// TODO Auto-generated method stub
System.out.println("Engine model year: "+engine.getModelyear());
}
}
Engine.java
package com.ds.cab.engine;
public class Engine {
private String modelyear;
public void setModelyear(String modelyear) {
this.modelyear = modelyear;
}
public String getModelyear() {
return modelyear;
}
}
Test.java
package ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ds.cab.car.Car;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("Beans.xml");
Car c = (Car)ctx.getBean(Car.class);
c.printData();
}
}
Error
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [E:\Prakhar\STS Workspace\StereoTyping01\bin\com\ds\cab\car\Car.class]; nested exception is java.lang.IllegalArgumentException
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:281)
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:242)
at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:84)
at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1435)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1425)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:184)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:140)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:111)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:243)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:131)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at ioc.Test.main(Test.java:10)
Caused by: java.lang.IllegalArgumentException
at org.springframework.asm.ClassReader.<init>(Unknown Source)
at org.springframework.asm.ClassReader.<init>(Unknown Source)
at org.springframework.asm.ClassReader.<init>(Unknown Source)
at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:52)
at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:80)
at org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:101)
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:257)
... 24 more
Create a Car bean and inject your engine bean into it (e represents your engine bean name):
<bean id="Car" class = "com.ds.cab.car.Car">
<constructor-arg ref="e"/>
</bean>
In your beans.xml,
Change component-scan into
<context:component-scan base-package="com.ds.cab.car" />
Remove engine bean declarion.
Add #Component annotation to Car Class.
I am working on Spring Boot Eureka Client Application with Ribbon Load Balancer.
I have two instances of the server registered with Eureka with the name "TEST". On the client side, I have the following code to fetch the server from Eureka.
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableEurekaClient
#RestController
public class EurekaConsumerApplication {
#Autowired
DiscoveryClient discoveryClient;
#Autowired
RestTemplate restTemplate;
#RequestMapping(value = "/",method = RequestMethod.GET)
String consumer(){
InstanceInfo instance = discoveryClient.getNextServerFromEureka("TEST", false);
URI uri = UriComponentsBuilder.fromUriString(instance.getHomePageUrl() + "baseDir")
.build()
.toUri();
String baseDir = restTemplate.getForObject(uri, String.class);
return baseDir;
}
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
application.yml
spring:
application:
name: consumer
info:
component: Consumer to fetch configuration
server:
port: 8090
eureka:
instance:
leaseRenewalIntervalInSeconds: 3
metadataMap:
instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${random.value}}}
client:
# Default values comes from org.springframework.cloud.netflix.eurek.EurekaClientConfigBean
region: default
registryFetchIntervalSeconds: 5
instanceInfoReplicationIntervalSeconds: 5
initialInstanceInfoReplicationIntervalSeconds: 5
serviceUrl:
defaultZone: http://localhost:8761/eureka/
availabilityZones:
default: ${APPLICATION_DOMAIN:${DOMAIN:defaultZone}}
However, when I hit the restful endpoint by using the following command, it gives an error:
curl http://localhost:8090/
This is the error:
{"exception":"java.lang.IllegalStateException","message":"org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No instances available for Samarths-MacBook-Pro.local","path":"/"}
Stacktrace:
2015-07-22 14:37:35.005 INFO 13841 --- [tp1334391583-19] c.netflix.loadbalancer.BaseLoadBalancer : Client:Samarths-MacBook-Pro.local instantiated a LoadBalancer:DynamicServerListLoadBalancer:{NFLoadBalancer:name=Samarths-MacBook-Pro.local,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2015-07-22 14:37:35.009 INFO 13841 --- [tp1334391583-19] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client Samarths-MacBook-Pro.local initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=Samarths-MacBook-Pro.local,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList#681eda37
2015-07-22 14:37:35.029 WARN 13841 --- [tp1334391583-19] o.eclipse.jetty.servlet.ServletHandler :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No instances available for Samarths-MacBook-Pro.local
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:808)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:295)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty..ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:68)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: No instances available for Samarths-MacBook-Pro.local
at org.springframework.cloud.netflix.ribbon.RibbonClientHttpRequestFactory.createRequest(RibbonClientHttpRequestFactory.java:64)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:76)
at org.springframework.web.client.Rlate.doExecute(RestTemplate.java:565)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:545)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:253)
at com.securityscorecard.eureka.consumer.EurekaConsumerApplication.consumer(EurekaConsumerApplication.java:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
... 38 common frames omitted
Looks like my server list is empty.
The RestTemplate you autowired is already connected to Ribbon. So you do a lookup by hand and then RestTemplate is trying to lookup the hostname passed in to ribbon. You have two options: 1) Don't use the netflix DiscoveryClient and pass the serviceId as a logical hostname to ribbon (http://TEST/myservice), 2) Don't use the autowired RestTemplate, create a new one for your class. My choice would be #1.
I got this working. The only change I had to make was in the way I was using RestTemplate api.
Error Code:
#Autowired
RestTemplate restTemplate;
#RequestMapping(value = "/",method = RequestMethod.GET)
String consumer(){
String baseDir = restTemplate.getForObject("TEST", String.class);
return baseDir;
}
Working Code:
#Autowired
RestTemplate restTemplate;
#RequestMapping(value = "/",method = RequestMethod.GET)
String consumer(){
String baseDir = restTemplate.getForObject("http://TEST", String.class);
return baseDir;
}
Solution:
The first parameter to restTemplate.getForObject should have the format of a URL. And the domain name should be the name of the service you want to discover.
Ex: http://TEST. Here, TEST is the name of my server registered to eureka registry
The question is already answered, but I found a workaround that seems neat and fixed our problem.
First declare a new #Component class and in it create a method that returns RestTemplate:
#Component
public class RestTemplateComponentFix{
#Autowired
SomeConfigurationYouNeed someConfiguration;
#LoadBalanced
public RestTemplate getRestTemplate() {
// TODO set up your restTemplate
rt.setRequestFactory( new HttpComponentsClientHttpRequestFactory() );
return rt;
}
}
After that just Autowire the restTemplateComponentFix in your class and when when you need the rest template call the restTemplate() method. Something like this:
#Service
public class someClass{
#Autowired
RestTemplateComponentFix restTemplateComponentFix;
public void methodUsingRestTemplate(){
// Some code...
RestTemplate rt = restTemplateComponentFix.getRestTemplate();
// Some code...
}
}
After that you can unit test with something like:
RestTemplate rt = Mockito.mock(RestTemplate.class)
when(restTemplateComponentFix.getRestTemplate()).thenReturn(rt);
when(rt.someMethod()).thenReturn(something);
Removing #LoadBalanced Annotation from RestTemplate works for me.
P.S: #LoadAnnotation is supposed to be applied only to Eureka Server which is your discovery server.
The question is already answered by #spencergibb, after trying #spencergibb way if you are still struggling with no instance avialable for ..MS... make sure that in pom.xml if you are using Netflix Eureka then avoid adding dependency for Netflix ribbon as Eureka itself internally uses ribbon.
This was causing problems for me.
RestTemplateBuilder works for me. As below-
#Service
public class someClass{
#Autowired
RestTemplateBuilder restTemplateBuilder;
public void methodUsingRestTemplate(){
restTemplateBuilder.build().getForObject("http://TEST", String.class);
}
}
Can be due to outdated release used in dependencies.
I was using a project from GitHub blog to understand the working of Microservices registry and discovery.
The dependency of netflix in that project was outdated,
spring-cloud-starter-netflix-eureka-server', version: '2.0.1.RELEASE'
After removing version, issue was solved as latest version would be used.
Question is not a duplicate as Hibernate is involved
As the James' answer partially solved the problem, I accepted it and opened a new question, please follow up here
I am trying to inject SessionFactory into a repository class; however, it looks like it does not work as the code returns NullPointer exception.
I cleaned and rebuilt the project but the issue still exist. I also put #Autowired on the setSessionFactory method but did not help.
Interface
public interface TestRep {
public void get(int id);
}
Class
#Repository
public class TestRepImpl implements TestRep{
#Autowired
SessionFactory sessionFactory;
public TestRepImpl() {
}
public TestRepImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Transactional
public void get(int id) {
String hql = "from Business where id=" + id;
Query query = sessionFactory.getCurrentSession().createQuery(hql);
....
pr-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:annotation-config/>
.....
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="TestRep" class="com.project.repository.TestRepImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
StackTrace
Mar 10, 2015 12:22:21 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [pr] in context with path [/project] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at com.project.repository.TestRepImpl.get(TestRepImpl.java:39)
at com.project.web.MainController.index(MainController.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Jars
MainController
#Controller
public class MainController {
#RequestMapping("/{viewName}.htm")
public String index(#PathVariable(value = "viewName") String viewName) {
System.err.println(viewName);
Test test = new Test();
test.get(1);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
#RequestMapping("/{viewName}/{viewName2}") //suburb/catname
public String index(#PathVariable(value = "viewName") String viewName, Model model) {
System.err.println(viewName);
if (isValidView(viewName)) {
model.addAttribute("viewName",viewName);
return "page";
}
return null;
}
private boolean isValidView(String viewName) {
switch (viewName) {
case "index":
case "aboutus":
return true;
}
return false;
}
}
Test
#Service
public class Test {
public void get(int i){
TestRepImpl test = new TestRepImpl();
test.get(i);
}
}
Hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">12</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping class="com.myproject.model.MyTable" />
....
You need to use Autowiring everywhere or your program won't work. Spring can only autowire beans that are present in the Spring application context, which is what your #Controller, #Service and #Repository annotations are supposed to do. However, these annotations are meaningless without a <context:component-scan base-package="your.base.package"> tag in your config XML.
So, assuming that your controller, service and DAO are all somewhere in the package com.repository, you need to add this line to your XML config.
<context:component-scan base-package="com.repository"/>
What this does is tells Spring to recursively search inside the foo.bar.baz package (and all sub-packages) for classes annotated with #Controller, #Service, #Repository and #Component, instantiate a singleton instance of them and make them eligible to be autowired into other classes.
You also need to modify your controller and service classes to use #Autowired. Spring can't manage your classes if you instantiate them with the new keyword. These beans are singletons (only one instance of them should ever exist in your program) for a reason.
Your controller needs to change as follows.
#Controller
public class MainController {
#Autowired
private TestService testService;
#RequestMapping("/{viewName}.htm")
public String index(#PathVariable(value = "viewName") String viewName) {
System.err.println(viewName);
testService.get(1);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
#RequestMapping("/{viewName}/{viewName2}") //suburb/catname
public String index(#PathVariable(value = "viewName") String viewName, Model model) {
System.err.println(viewName);
if (isValidView(viewName)) {
model.addAttribute("viewName",viewName);
return "page";
}
return null;
}
private boolean isValidView(String viewName) {
switch (viewName) {
case "index":
case "aboutus":
return true;
}
return false;
}
}
Notice that you Autowire your service class into your controller.
Your service class needs to implement an interface. Spring does all this autowiring magic using interfaces. You cannot autowire a class that does not implement an interface, unless you specifically create an instance of that class in your XML config.
Your service class needs to change as follows:
#Service
public class TestServiceImpl implements TestService {
#Autowired
private TestRepDao testDao;
#Transactional
public void get(int i){
testDao.get(i);
}
}
and create an interface called TestService.
public interface TestService{
public void get(int i);
}
and then your DAO becomes
#Repository
public class TestRepDaoImpl implements TestRepDao{
#Autowired
private SessionFactory sessionFactory;
public void get(int id) {
String hql = "from Business where id=" + id;
Query query = sessionFactory.getCurrentSession().createQuery(hql);
}
}
which implements the interface TestRepDao:
public interface TestRepDao{
public void get(int id);
}
you can also remove the declaration of
<bean id="TestRep" class="com.project.repository.TestRepImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
from your XML configuration.
As you can see I've changed a few class names to better fit with the Spring convention. Your application is supposed to layer down from Controller to Service Class to DAO and back out again. This should work providing you follow the steps I've laid out here.
A few things to keep in mind:
Spring hates the new keyword. If you find yourself using it, you are probably doing something wrong.
There is only ever one instance of any of your classes that Spring picks up with the component scan in your entire application. DO NOT use these classes to store persistent data or states. That path is full of threading issues, race conditions and pits full of acid spiders.
Read and re-read the documentation, these are not easy concepts to pick up if you have never used Spring before. Spring is super easy to use, once you understand how it works, and how it expects you to use it.
Spring works on interfaces. If your class doesn't implement an interface, Spring can't proxy it without using AspectJ Load Time Weaving, which is a conversation for another day, and not something you should be using, just starting out. If you don't know why Spring needs to create a proxy of your object, you need to re-read the documentation until you understand the application context.
I moved the #Transactional annotation into the Service class. This is because the DAO should only be concerned with accessing and retrieving the data from the database, NOT having to manage the connection/session to the database, that is the job of the service class.
I'm guessing you started using the new keyword after hitting exceptions saying something similar to
No qualifying bean of type found for dependency TestService.
This is Spring telling you that it doesn't have a bean that can be autowired into the TestService field on whatever class. Listen when Spring is telling you things, it will save you a lot of bother.
Don't be discouraged, I faced all these problems when I was trying to learn how to use Spring, but I got through it and Spring is second nature to me now.