SpringBoot can't scan Controller and get the URL mapping - java

I just wrote a Springboot application as a testing Webserver which origins from spring.io.
It packaged initially in "jar", changed it to "war" file.
And get the application class code as below:
package com.ronzhong;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.context.WebApplicationContext;
#SpringBootApplication(scanBasePackages={"com.ronzhong.libraryManagement"})
public class LibraryManagementApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
application.application().setBannerMode(Mode.OFF);
return application.sources(SpringApplicationBuilder.class);
}
protected WebApplicationContext run(SpringApplication application) {
return (WebApplicationContext) application.run();
}
// public static void main(String[] args) {
// SpringApplication.run(LibraryManagementApplication.class, args);
//}
}
and the controller is :
package com.ronzhong.libraryManagement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.*;
//#CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
#RestController
#RequestMapping("/api")
public class CounterController {
#Autowired
private BookService bookService;
#PostMapping
public boolean add(#RequestBody Book book){
return bookService.add(book);
}
#RequestMapping(value = "/books", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Book[] get(){
return bookService.getBooks();
}
#RequestMapping(value = "{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Book findOne(#PathVariable("id") int id){
return bookService.findById(id);
}
}
And I also checked the
"Dynamic Web Module" in the project facets.
Finally, I got these logs when launch tomcat server with this war file generated.
INFO: 2 Spring WebApplicationInitializers detected on classpath
2018-11-28 10:43:31.925 INFO 14888 --- [ main] c.ronzhong.LibraryManagementApplication : Starting LibraryManagementApplication on ronzhongmachine with PID 14888 (C:\Users\ronzhong\workspace_testserver\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\library-Management\WEB-INF\classes started by ronzhong in C:\tools_installers\eclipse-jee-2018-09-win32-x86_64\eclipse)
2018-11-28 10:43:32.002 INFO 14888 --- [ main] c.ronzhong.LibraryManagementApplication : No active profile set, falling back to default profiles: default
2018-11-28 10:43:33.910 INFO 14888 --- [ main] o.a.c.c.C.[.[.[/library-Management] : Initializing Spring embedded WebApplicationContext
2018-11-28 10:43:33.911 INFO 14888 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1604 ms
2018-11-28 10:43:34.362 INFO 14888 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'errorPageFilter' to: [/*]
2018-11-28 10:43:34.704 INFO 14888 --- [ main] c.ronzhong.LibraryManagementApplication : Started LibraryManagementApplication in 5.958 seconds (JVM running for 36.407)
2018-11-28 10:43:34.955 INFO 14888 --- [ main] org.apache.coyote.ajp.AjpNioProtocol : Starting ProtocolHandler ["ajp-nio-8009"]
2018-11-28 10:43:34.968 INFO 14888 --- [ main] org.apache.catalina.startup.Catalina : Server startup in 28177 ms
There're no mappings info in the logs.
And if I request with http://localhost:8080/api/books, it will get 404 error.
But the logs hasn't change even a little.
So I googled the potential causes, and excluded those causes temporarily:
springboot application does not scan the package which controller locates?
I moved springboot application class to the uplevel package, and also specified what kind of package it should scan.
While you see, it doesn't work.
the annotation issue?
Some people say we should use #RestController annotation instead of #Controller, better add the #ResponseBody, while I did.
it does't work, either.
the deployment issue?
don't know, I did changed the build path of this project, which generated jar file and war file normally, but webapp folder is empty, since I don't have any static resource, I think it's fine, right?
Anyone can help me? very appreciate for your answer, thanks in advance.

From the logs, I can see that your war file name is library-Management, whichh means its deloyed under this folder, as logs states. So you should check http://localhost:8080/library-Management/api/books instead.
You get 404 from Tomcat, it doesnt hit your app at all, this is ehy you dont see any logs.

Related

SLF4J logger not logging

The log file exists and logs are generated but it isn't logging Processing index request in the logs.
Is the code correct? When index page is accessed the thymleaf content "DevOps" is being retrieved and displayed in index.html but no logs from logger.info in the logs.
package com.example.devops.web;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class WelcomeController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#RequestMapping("/")
public String welcome(Model model) {
logger.info("Processing index request");
model.addAttribute("course", "DevOps");
return "index";
}
}
Log entires:
021-08-27 18:41:08.557 [INFO ] [localhost-startStop-1] c.e.d.ServletInitializer - Starting ServletInitializer v1.3.1-SNAPSHOT using Java 1.8.0_301 on DESKTOP-6O551TV with PID 23756 (F:\Devops\apache-tomcat-8.5.70\webapps\devops\WEB-INF\classes started by user in F:\Devops\apache-tomcat-8.5.70\bin)
2021-08-27 18:41:08.615 [INFO ] [localhost-startStop-1] c.e.d.ServletInitializer - The following profiles are active: dev
2021-08-27 18:41:09.573 [INFO ] [localhost-startStop-1] o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 847 ms
2021-08-27 18:41:10.215 [INFO ] [localhost-startStop-1] o.s.b.a.w.s.WelcomePageHandlerMapping - Adding welcome page template: index
2021-08-27 18:41:10.374 [INFO ] [localhost-startStop-1] c.e.d.ServletInitializer - Started ServletInitializer in 2.416 seconds (JVM running for 11.278)
Actually its working as expected. application-dev.properties file did not have full path of the log and a couple of commits were missing.
It is working.

org.springframework.beans.factory.BeanCreationException while try to connect my mongodb cloud data base to my spring application

I was trying to create my basic spring application and try to connect to my MongoDB database.
so a create my entity
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document
#Data #AllArgsConstructor #NoArgsConstructor #ToString
public class MyProduct {
#Id
private String id;
private String name;
private int price;
}
my repository
import com.nizar.back.demo.entities.MyProduct;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource
public interface MyProductRepository extends MongoRepository<MyProduct,String> {
}
my application.properties
server.port=8093
spring.data.mongodb.uri=mongodb://<my username>:<my password>#cluster0.zgrrb.mongodb.net/appDatabase?retryWrites=true&w=majority
and this is my application class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
#SpringBootApplication
#EnableAutoConfiguration(exclude={ DataSourceAutoConfiguration.class, MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
what i notice that i have this error when i try to run my application, and i didn't understant why ?
2021-07-21 18:04:49.921 INFO 7524 --- [ main] com.nizar.back.demo.DemoApplication : Starting DemoApplication using Java 1.8.0_291 on DESKTOP-6PB4U74 with PID 7524 (C:\dev projects\spring project\demo\target\classes started by abdel in C:\dev projects\spring project\demo)
2021-07-21 18:04:49.924 INFO 7524 --- [ main] com.nizar.back.demo.DemoApplication : No active profile set, falling back to default profiles: default
2021-07-21 18:04:50.411 INFO 7524 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode.
2021-07-21 18:04:50.459 INFO 7524 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 43 ms. Found 1 MongoDB repository interfaces.
2021-07-21 18:04:50.724 WARN 7524 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myProductRepository' defined in com.nizar.back.demo.dao.MyProductRepository defined in #EnableMongoRepositories declared on MongoRepositoriesRegistrar.EnableMongoRepositoriesConfiguration: Cannot resolve reference to bean 'mongoTemplate' while setting bean property 'mongoOperations'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mongoTemplate' available
2021-07-21 18:04:50.732 INFO 7524 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-07-21 18:04:50.749 ERROR 7524 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
A component required a bean named 'mongoTemplate' that could not be found.
I just did this project to learn about spring boot. and i just need to find why i have this error and how i can solve it
it didn't choose the right version of the driver.
so I change the drive version on https://cloud.mongodb.com/ to 3.4 or later and it give me an other url to connect and it work
mongodb://<MyUsername>:<Mypassword>#cluster0-shard-00-00.zgrrb.mongodb.net:27017,cluster0-shard-00-01.zgrrb.mongodb.net:27017,cluster0-shard-00-02.zgrrb.mongodb.net:27017/myFirstDatabase?ssl=true&replicaSet=atlas-sr24zl-shard-0&authSource=admin&retryWrites=true&w=majority

Why does Spring execute #Cacheable keyGenerator 2 times for a single invocation of #Cacheable annotated method

Why does Spring execute my custom #Cacheable keyGenerator twice for a single invocation of a method annotated #Cacheable, why not do it just once.
My KeyGenerator implementation
package com.example.demo;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* Custom key generator
*/
#Component(value = "customerKeyGenerator")
public class CustomerKeyGen implements KeyGenerator
{
#Override
public Object generate(Object target, Method method, Object... params)
{
System.out.println("Generating a key");
ArrayList<String> customerNames = (ArrayList<String>) params[0];
return customerNames.hashCode();
}
}
My Method annotated with #Cacheable with custom keyGenerator
package com.example.demo;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
#Component
public class CustomerService {
#Cacheable(value = "customersCache", keyGenerator = "customerKeyGenerator")
public int getCountOfCustomers(ArrayList<String> customerNames) {
return customerNames.size();
}
}
Spring Rest Controller which invokes the method annotated with #Cacheable
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
#Controller
public class CustomerController {
#Autowired
CustomerService customerService;
#RequestMapping("/")
#ResponseBody
String home() {
return "Hello World!";
}
#RequestMapping("/countCustomers")
#ResponseBody
String countCustomers() {
ArrayList<String> customerNames = new ArrayList<>();
customerNames.add("john");
customerNames.add("bill");
return "countOfCustomers=" + String.valueOf(customerService.getCountOfCustomers(customerNames));
}
}
When I make a single invocation of the method annotated with #Cacheable with my custom keyGenerator, I see 2 executions in my log and dubugger of
System.out.println("Generating a key");
Curl to trigger method call invocation
curl http://127.0.0.1:8080/countCustomers
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 18 100 18 0 0 18 0 0:00:01 --:--:-- 0:00:01
76countOfCustomers=2
Log
I have the following setting in application properties to enable tracing of the cache
logging.level.org.springframework.cache=TRACE
...
2018-08-27 11:56:53.753 INFO 18756 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-08-27 11:56:53.757 INFO 18756 --- [ main] c.example.demo.TestCacheableApplication : Started TestCacheableApplication in 3.543 seconds (JVM running for 5.137)
2018-08-27 11:56:58.411 INFO 18756 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-08-27 11:56:58.411 INFO 18756 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2018-08-27 11:56:58.446 INFO 18756 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 35 ms
Generating a key
2018-08-27 11:56:58.480 TRACE 18756 --- [nio-8080-exec-1] o.s.cache.interceptor.CacheInterceptor : Computed cache key '104328221' for operation Builder[public int com.example.demo.CustomerService.getCountOfCustomers(java.util.ArrayList)] caches=[customersCache] | key='' | keyGenerator='customerKeyGenerator' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
2018-08-27 11:56:58.480 TRACE 18756 --- [nio-8080-exec-1] o.s.cache.interceptor.CacheInterceptor : No cache entry for key '104328221' in cache(s) [customersCache]
Generating a key
2018-08-27 11:56:58.480 TRACE 18756 --- [nio-8080-exec-1] o.s.cache.interceptor.CacheInterceptor : Computed cache key '104328221' for operation Builder[public int com.example.demo.CustomerService.getCountOfCustomers(java.util.ArrayList)] caches=[customersCache] | key='' | keyGenerator='customerKeyGenerator' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
Conceptually, I would have thought Spring would need to run the keyGenerator only once, use it firstly to lookup the cache, and if not found, when the method is complete, use that same key to put to the cache. So I don't understand why I see this running twice.
My issues with this:
I am confused with how it works and why
The logging and debugging become confusing
Potential performance impact, even though keyGeneration implementation should be cheap, why do it multiple times.
I think I know why, key is generated once for lookup in cache, and once for putting into the cache. Not sure why it works that way, but appears to be what is happening.

Scheduler not running in Spring Boot

I have created a Spring Boot application. I have configured my class that contains the scheduler method startService().
Below is my code :
Service Class :
package com.mk.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.mk.envers.model.BossExtChange;
import com.mk.envers.model.BossExtChangeRepository;
#Component
public class EnverseDemoService {
#Autowired
BossExtChangeRepository bossExtChangeRepository;
#Scheduled(fixedRate = 30000)
public void startService() {
System.out.println("Calling startService()");
BossExtChange bossExtChange = bossExtChangeRepository.findById(5256868L);
System.out.println("bossExtChange.getDescription()--->"+bossExtChange.getDescription());
System.out.println("Ending startService()");
}
}
Main Class :
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableScheduling;
#SpringBootApplication
#EnableScheduling
#PropertySource("classpath:application.properties")
public class EnverseDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EnverseDemoApplication.class, args);
}
}
I have annotated the class as #Component and also method as #Scheduled(fixedRate = 30000) that will running as a scheduler. But while running the application as Spring Boot the scheduler does not trigger. The console show the below message:
2016-02-03 10:56:47.708 INFO 10136 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2016-02-03 10:56:47.721 INFO 10136 --- [ main] com.mk.envers.EnverseDemoApplication : Started EnverseDemoApplication in 3.231 seconds (JVM running for 3.623)
2016-02-03 10:56:47.721 INFO 10136 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#49e202ad: startup date [Wed Feb 03 10:56:44 IST 2016]; root of context hierarchy
2016-02-03 10:56:47.721 INFO 10136 --- [ Thread-2] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2016-02-03 10:56:47.736 INFO 10136 --- [ Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
Can anyone please help me out.
May be you can solve this problem by adding the #ComponentScan annotation in the configuration file
#SpringBootApplication
#EnableScheduling
#ComponentScan(basePackages = "com.mk.service")
#PropertySource("classpath:application.properties")
public class EnverseDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EnverseDemoApplication.class, args);
}
}
I was able to solve the issue, I forgot to provide #service level annotation,
I have created the check List for #Scheduler, kindly go through every point one by one, It will help you to solve the issue.
Check for the #EnableScheduling on SpringBoot Main class.
Scheduled method should be annotated with #Scheduled, Follow the #Scheduled Method rules. a method should have the void return type, a method should not accept any parameters.
Make sure the class should be annotated with #Service or #Component Annotation so SpringBoot can make the object of that class.
The package of the scheduler jobs should be under the main Application class's package. e.g com.company is your main application class package then scheduler class package should be com.company.scheduler,
If you are using Cron expression confirm the same e.g #Scheduled( cron = "0 0/2 * * * ?"), This Cron expression will schedule the task for every 2 min.
Feel free to add more points in the comment so it will help to solve the issue.
It must be that you forgot to add #EnableScheduling annotation in your app class.
public static void main(String[] args) {
context = SpringApplication.run(YouApplication.class, args);
}
I was finally able to solve the above issue, I changed the package of my service class EnverseDemoService from package com.mk.service; to com.mk.envers.service;. This is because if the main configuration class EnverseDemoApplication is present in the package com.mk.envers. All the other classes in the boot application should be in the qualifying package. Eg: com.mk.envers.*;
In my case, was the lazy-initialization with value true which was preventing my #Component to be loaded by Spring at startup and #Scheduled method was never running.
Make sure the Spring Boot lazy initialization is disabled.
Please check if in application.properties you have
"spring.main.lazy-initialization=true"
Remove this from application.properties.
Even if you have all the configuration correct, this simple line will enable lazy loading due to which your #Component will initalize during application start.
As Swapnil already mentioned all the check-points to make sure while using cron. One additional thing you should do:
Always verify your cron expression whether it's in right format or not, using below reference site - http://www.freeformatter.com/cron-expression-generator-quartz.html#

Switch off DispatcherServlet on Spring Boot

How can I disable the DispatcherServlet on SpringBoot, even trying to disable it via servlet registration the uri mapping appears on the log:
#Bean
public ServletRegistrationBean servletRegistrationBean(final DispatcherServlet dispatcherServlet) {
final ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet);
servletRegistrationBean.setEnabled(false);
return servletRegistrationBean;
}
LOG
2015-06-10 10:39:57.552 INFO 7032 --- [ main] o.s.b.c.e.ServletRegistrationBean : Servlet dispatcherServlet was not registered (disabled)
2015-06-10 10:39:57.553 INFO 7032 --- [ main] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
Thanks any help!
I added below code into my main class, and the servlet was removed from log.
#SpringBootApplication(exclude = { DispatcherServletAutoConfiguration.class })
From Spring boot docs here
Spring Boot wants to serve all content from the root of your application / down. If you would rather map your own servlet to that URL you can do it, but of course you may lose some of the other Boot MVC features. To add your own servlet and map it to the root resource just declare a #Bean of type Servlet and give it the special bean name dispatcherServlet (You can also create a bean of a different type with that name if you want to switch it off and not replace it).
If you exclude DispatcherServletAutoConfiguration.class,
then you need to exclude ErrorMvcAutoConfiguration.class as well, or at least I did.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#SpringBootApplication(exclude = { DispatcherServletAutoConfiguration.class, ErrorMvcAutoConfiguration.class})
#EnableAspectJAutoProxy
public class CoreApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(CoreApplication.class);
}
}

Categories

Resources