Print all the Spring beans that are loaded - java

Is there a way to print all the spring beans that are loaded on startup?I am using Spring 2.0.

Yes, get ahold of ApplicationContext and call .getBeanDefinitionNames()
You can get the context by:
implementing ApplicationContextAware
injecting it with #Inject / #Autowired (after 2.5)
use WebApplicationContextUtils.getRequiredWebApplicationContext(..)
Related: You can also detect each bean's registration by registering a BeanPostprocessor bean. It will be notified for each bean.

public class PrintBeans {
#Autowired
ApplicationContext applicationContext;
public void printBeans() {
System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames()));
}
}

With Spring Boot and the actuator starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
you can check the endpoint /beans

Print all bean names and its classes:
package com.javahash.spring.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
public class HelloWorldController {
#Autowired
private ApplicationContext applicationContext;
#RequestMapping("/hello")
public String hello(#RequestParam(value="key", required=false, defaultValue="World") String name, Model model) {
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName + " : " + applicationContext.getBean(beanName).getClass().toString());
}
model.addAttribute("name", name);
return "helloworld";
}
}

applicationContext.getBeanDefinitionNames() does not show the beans which are registered without BeanDefinition instance.
package io.velu.core;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan
public class Core {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Core.class);
String[] singletonNames = context.getDefaultListableBeanFactory().getSingletonNames();
for (String singleton : singletonNames) {
System.out.println(singleton);
}
}
}
Console Output
environment
systemProperties
systemEnvironment
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
messageSource
applicationEventMulticaster
lifecycleProcessor
As you can see in the output, environment, systemProperties, systemEnvironment beans will not be shown using context.getBeanDefinitionNames() method.
Spring Boot
For spring boot web applications, all the beans can be listed using the below endpoint.
#RestController
#RequestMapping("/list")
class ExportController {
#Autowired
private ApplicationContext applicationContext;
#GetMapping("/beans")
#ResponseStatus(value = HttpStatus.OK)
String[] registeredBeans() {
return printBeans();
}
private String[] printBeans() {
AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
if (autowireCapableBeanFactory instanceof SingletonBeanRegistry) {
String[] singletonNames = ((SingletonBeanRegistry) autowireCapableBeanFactory).getSingletonNames();
for (String singleton : singletonNames) {
System.out.println(singleton);
}
return singletonNames;
}
return null;
}
}
[
"autoConfigurationReport",
"springApplicationArguments",
"springBootBanner",
"springBootLoggingSystem",
"environment",
"systemProperties",
"systemEnvironment",
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor",
"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory",
"org.springframework.boot.autoconfigure.condition.BeanTypeRegistry",
"org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry",
"propertySourcesPlaceholderConfigurer",
"org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store",
"preserveErrorControllerTargetClassPostProcessor",
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor",
"org.springframework.context.annotation.internalRequiredAnnotationProcessor",
"org.springframework.context.annotation.internalCommonAnnotationProcessor",
"org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor",
"org.springframework.scheduling.annotation.ProxyAsyncConfiguration",
"org.springframework.context.annotation.internalAsyncAnnotationProcessor",
"methodValidationPostProcessor",
"embeddedServletContainerCustomizerBeanPostProcessor",
"errorPageRegistrarBeanPostProcessor",
"messageSource",
"applicationEventMulticaster",
"org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat",
"tomcatEmbeddedServletContainerFactory",
"org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration$TomcatWebSocketConfiguration",
"websocketContainerCustomizer",
"spring.http.encoding-org.springframework.boot.autoconfigure.web.HttpEncodingProperties",
"org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration",
"localeCharsetMappingsCustomizer",
"org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration",
"serverProperties",
"duplicateServerPropertiesDetector",
"spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties",
"org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$DefaultErrorViewResolverConfiguration",
"conventionErrorViewResolver",
"org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration",
"errorPageCustomizer",
"servletContext",
"contextParameters",
"contextAttributes",
"spring.mvc-org.springframework.boot.autoconfigure.web.WebMvcProperties",
"spring.http.multipart-org.springframework.boot.autoconfigure.web.MultipartProperties",
"org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration",
"multipartConfigElement",
"org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration",
"org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration",
"dispatcherServlet",
"dispatcherServletRegistration",
"requestContextFilter",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration",
"hiddenHttpMethodFilter",
"httpPutFormContentFilter",
"characterEncodingFilter",
"org.springframework.context.event.internalEventListenerProcessor",
"org.springframework.context.event.internalEventListenerFactory",
"reportGeneratorApplication",
"exportController",
"exportService",
"org.springframework.boot.autoconfigure.AutoConfigurationPackages",
"org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration",
"spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties",
"standardJacksonObjectMapperBuilderCustomizer",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration",
"jsonComponentModule",
"jacksonObjectMapperBuilder",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration",
"jacksonObjectMapper",
"org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration",
"org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration",
"org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration",
"org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration",
"defaultValidator",
"org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration",
"error",
"beanNameViewResolver",
"errorAttributes",
"basicErrorController",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter",
"mvcContentNegotiationManager",
"org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration",
"stringHttpMessageConverter",
"org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration",
"mappingJackson2HttpMessageConverter",
"org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration",
"messageConverters",
"mvcConversionService",
"mvcValidator",
"requestMappingHandlerAdapter",
"mvcResourceUrlProvider",
"requestMappingHandlerMapping",
"mvcPathMatcher",
"mvcUrlPathHelper",
"viewControllerHandlerMapping",
"beanNameHandlerMapping",
"resourceHandlerMapping",
"defaultServletHandlerMapping",
"mvcUriComponentsContributor",
"httpRequestHandlerAdapter",
"simpleControllerHandlerAdapter",
"handlerExceptionResolver",
"mvcViewResolver",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter$FaviconConfiguration",
"faviconRequestHandler",
"faviconHandlerMapping",
"defaultViewResolver",
"viewResolver",
"welcomePageHandlerMapping",
"org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration",
"objectNamingStrategy",
"mbeanServer",
"mbeanExporter",
"org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration",
"springApplicationAdminRegistrar",
"org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration",
"org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration",
"spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties",
"org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration",
"multipartResolver",
"org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$RestTemplateConfiguration",
"restTemplateBuilder",
"org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration",
"spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$RestartConfiguration",
"fileSystemWatcherFactory",
"classPathRestartStrategy",
"classPathFileSystemWatcher",
"hateoasObjenesisCacheDisabler",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration$LiveReloadServerConfiguration",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration",
"optionalLiveReloadServer",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration",
"lifecycleProcessor"
]

You could try calling
org.springframework.beans.factory.ListableBeanFactory.getBeansOfType(Object.class)
Or turn on debug logging for org.springframework. (In spring boot, that's using a parameter --logging.level.org.springframework=DEBUG)

Here is another way to print all the bean names from the spring application context:
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/***********************************************************************************************************
* Java File: MainApplication.java
* Description: Main class to run the application.
*
***********************************************************************************************************/
#SpringBootApplication
public class MainApplication {
private static final Logger logger = LogManager.getLogger(MainApplication.class);
public static void main(String[] args)
{
final ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
final AtomicInteger counter = new AtomicInteger(0);
logger.info("**************** START: Total Bean Objects: {} ******************", context.getBeanDefinitionCount());
Arrays.asList(context.getBeanDefinitionNames())
.forEach(beanName -> {
logger.info("{}) Bean Name: {} ", counter.incrementAndGet(), beanName);
});
logger.info("**************** END: Total Bean: {} ******************", context.getBeanDefinitionCount());
}
}
Sample Output:
2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:18] - **************** START: Total Bean Objects: 564 ******************
...........................
2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 460) Bean Name: mvcPathMatcher
2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 461) Bean Name: mvcUrlPathHelper
2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 462) Bean Name: viewControllerHandlerMapping
2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 463) Bean Name: beanNameHandlerMapping
2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:22] - 464) Bean Name: resourceHandlerMapping
...........................
2019-11-27 20:08:02.821 INFO [main] [c.c.a.MainApplication:25] - **************** END: Total Bean: 564 ******************

Using spring-boot-starter-actuator you can easily access all bean.
Here is the setup process:
Add dependency into gradle:
Add bellow into gradle file:
compile("org.springframework.boot:spring-boot-starter-actuator")
Enable security on application.properties:
Add management.security.enabled=false into your application.property file
call /beans endpoint:
After that setup spring will enable some metrics related endpoints.
One of its endpoint is /beans
After calling this endpoints it will provide a json file that contains all of your bean including it's dependency and scope.
Here is an example json file:
[{"context":"application:8442","parent":null,"beans":[{"bean":"beanName","aliases":[],"scope":"singleton","type":"packageName$$4b46c703","resource":"null","dependencies":["environment","beanName1","beanName2"]},{"bean":"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory","aliases":[],"scope":"singleton","type":"org.springframework.core.type.classreading.CachingMetadataReaderFactory","resource":"null","dependencies":[]}]
For more info visit bellow links:
Building a RESTful Web Service with Spring Boot Actuator
Spring Boot Actuator: Health check, Auditing, Metrics gathering
Spring Boot Actuator: Production-ready features
Hope this will help you. Thanks :)

Related

Broadleaf Commerce Embedded Solr cannot run with root user

I download a fresh 6.1 broadleaf-commerce and run my local machine via java -javaagent:./admin/target/agents/spring-instrument.jar -jar admin/target/admin.jar successfully on mine macbook. But in my centos 7 I run sudo java -javaagent:./admin/target/agents/spring-instrument.jar -jar admin/target/admin.jar with following error
2020-10-12 13:20:10.838 INFO 2481 --- [ main] c.b.solr.autoconfigure.SolrServer : Syncing solr config file: jar:file:/home/mynewuser/seafood-broadleaf/admin/target/admin.jar!/BOOT-INF/lib/broadleaf-boot-starter-solr-2.2.1-GA.jar!/solr/standalone/solrhome/configsets/fulfillment_order/conf/solrconfig.xml to: /tmp/solr-7.7.2/solr-7.7.2/server/solr/configsets/fulfillment_order/conf/solrconfig.xml
*** [WARN] *** Your Max Processes Limit is currently 62383.
It should be set to 65000 to avoid operational disruption.
If you no longer wish to see this warning, set SOLR_ULIMIT_CHECKS to false in your profile or solr.in.sh
WARNING: Starting Solr as the root user is a security risk and not considered best practice. Exiting.
Please consult the Reference Guide. To override this check, start with argument '-force'
2020-10-12 13:20:11.021 ERROR 2481 --- [ main] c.b.solr.autoconfigure.SolrServer : Problem starting Solr
Here is the source code of solr configuration, I believe it is the place to change the configuration to run with the argument -force in programming way.
package com.community.core.config;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.broadleafcommerce.core.search.service.SearchService;
import org.broadleafcommerce.core.search.service.solr.SolrConfiguration;
import org.broadleafcommerce.core.search.service.solr.SolrSearchServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
*
*
* #author Phillip Verheyden (phillipuniverse)
*/
#Component
public class ApplicationSolrConfiguration {
#Value("${solr.url.primary}")
protected String primaryCatalogSolrUrl;
#Value("${solr.url.reindex}")
protected String reindexCatalogSolrUrl;
#Value("${solr.url.admin}")
protected String adminCatalogSolrUrl;
#Bean
public SolrClient primaryCatalogSolrClient() {
return new HttpSolrClient.Builder(primaryCatalogSolrUrl).build();
}
#Bean
public SolrClient reindexCatalogSolrClient() {
return new HttpSolrClient.Builder(reindexCatalogSolrUrl).build();
}
#Bean
public SolrClient adminCatalogSolrClient() {
return new HttpSolrClient.Builder(adminCatalogSolrUrl).build();
}
#Bean
public SolrConfiguration blCatalogSolrConfiguration() throws IllegalStateException {
return new SolrConfiguration(primaryCatalogSolrClient(), reindexCatalogSolrClient(), adminCatalogSolrClient());
}
#Bean
protected SearchService blSearchService() {
return new SolrSearchServiceImpl();
}
}
Let me preface this by saying you would be better off simply not starting the application as root. If you are in Docker, you can use the USER command to switch to a non-root user.
The Solr server startup in Broadleaf Community is done programmatically via the broadleaf-boot-starter-solr dependency. This is the wrapper around Solr that ties it to the Spring lifecycle. All of the real magic happens in the com.broadleafcommerce.solr.autoconfigure.SolrServer class.
In that class, you will see a startSolr() method. This method is what adds startup arguments to Solr.
In your case, you will need to mostly copy this method wholesale and use cmdLine.addArgument(...) to add additional arguments. Example:
class ForceStartupSolrServer extends SolrServer {
public ForceStartupSolrServer(SolrProperties props) {
super(props);
}
protected void startSolr() {
if (!isRunning()) {
if (!downloadSolrIfApplicable()) {
throw new IllegalStateException("Could not download or expand Solr, see previous logs for more information");
}
stopSolr();
synchConfig();
{
CommandLine cmdLine = new CommandLine(getSolrCommand());
cmdLine.addArgument("start");
cmdLine.addArgument("-p");
cmdLine.addArgument(Integer.toString(props.getPort()));
// START MODIFICATION
cmdLine.addArgument("-force");
// END MODIFICATION
Executor executor = new DefaultExecutor();
PumpStreamHandler streamHandler = new PumpStreamHandler(System.out);
streamHandler.setStopTimeout(1000);
executor.setStreamHandler(streamHandler);
try {
executor.execute(cmdLine);
created = true;
checkCoreStatus();
} catch (IOException e) {
LOG.error("Problem starting Solr", e);
}
}
}
}
}
Then create an #Configuration class to override the blAutoSolrServer bean created by SolrAutoConfiguration (note the specific package requirement for org.broadleafoverrides.config):
package org.broadleafoverrides.config;
public class OverrideConfiguration {
#Bean
public ForceStartupSolrServer blAutoSolrServer(SolrProperties props) {
return new ForceStartupSolrServer(props);
}
}

Geting list of protobuf message objects from the SpringBoot

I want to get a list of protobuf message objects from the Spring boot app.
I did manage to get a single protobuf message object from the app but getting a list of them throws exception.
...
2020-01-24 14:57:02.359 ERROR 15883 --- [nio-8081-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet$Parser]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ImmutableCollections$ListN[0]->com.example.demo.Lecture["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ImmutableCollections$ListN[0]->com.example.demo.Lecture["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.10.2.jar:2.10.2]
...
My code (simplified).
tl;dr
create Spring boot app
generate class from proto file
try return List of generated class objects (RESTful)
My code (simplified).
Controler
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#Slf4j
#org.springframework.web.bind.annotation.RestController
#RequestMapping("/timetable")
public class RestController {
#PostMapping("/single") // Works
private Lecture getLecture(#RequestBody Lecture lecture) {
log.info("Single2 got: {}", lecture);
return Lecture.newBuilder(lecture)
.setDuration(lecture.getDuration() +1)
.build();
}
#GetMapping("/list") // Does not work
private #ResponseBody List<Lecture> getLectures() {
return List.of(
Lecture.newBuilder()
.setDuration(1)
.setWeekDay(Lecture.WeekDay.MONDAY)
.setModule(Module.newBuilder().setName("Math1").build())
.build()
// ...
);
}
}
App
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
import org.springframework.http.converter.protobuf.ProtobufJsonFormatHttpMessageConverter;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
#Primary
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufJsonFormatHttpMessageConverter();
}
}
pom.xml
<!-- ... -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://dzone.com/articles/exposing-microservices-over-rest-protocol-buffers-->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.1</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.11.1</version>
</dependency>
</dependencies>
<!-- ... -->
I generate message objects using:
#!/bin/bash
SRC_DIR=../proto
DST_DIR=../../../target/
mkdir -p $DST_DIR
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/college.proto
proto file
syntax = "proto3";
package my.college;
option java_multiple_files = true;
option java_package = "com.example.demo";
message Module {
string name = 1;
// ... other
}
message Lecture {
WeekDay weekDay = 1;
Module module = 2;
uint32 duration = 3;
// ... other
enum WeekDay {
SUNDAY = 0;
MONDAY = 1;
// ...
}
}
I did found simmilar issue but it had no solution.
Explanation
Spring will choose the HttpMessageConverter that matches the appropriate converter for the object type of your response body. In this case, it is likely choosing MappingJackson2HttpMessageConverter of the ProtobufJsonFormatHttpMessageConverter because your response body has type List.
MappingJackson2HttpMessageConverter implements HttpMessageConverter<Object>
ProtobufJsonFormatHttpMessageConverter implements HttpMessageConverter<Message>
Since ProtobufJsonFormatHttpMessageConverter does not support serializing a List type, we can instead tell the MappingJackson2HttpMessageConverter how to serialize the Message type through configuration.
Solution
A bean of type Jackson2ObjectMapperBuilderCustomizer can be used to register a serializer for Message types.
#Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return o -> o.serializerByType(Message.class, new JsonSerializer<Message>() {
#Override
public void serialize(Message value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeRawValue(JsonFormat.printer().print(value));
}
});
}
Workaround
I couldn't find a solution to the problem so came up with a workaround.
Instead of returning generated protobuf message objects I returned wrappers for those objects. Using Lombok annotation it could be done:
import lombok.Data;
#Data // Lombok magic
public class Module {
private String name;
// ...
public Module(ie.gmit.proto.Module moduleProto){
this.name = moduleProto.getName();
// ...
}
}
This workaround doesn't feel very bad as it uses standard Spring boot dependencies.

Can't run SpringBoot Application

I am new to Spring and i have to make an "HelloWorld" Application. After several attempts, i can't solve my problem.
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CiaoMondoApplication {
public static void main(String[] args) {
SpringApplication.run(CiaoMondoApplication.class, args);
}
} // that's the Application
package com.example.demo;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
public class CiaoMondoController {
#RequestMapping("/")
public String index() {
return "HelloWorld";
}
} // and that's the controller
Below the output, when i try to run the Application with Eclipse:
2019-06-11 11:09:33.089 INFO 9572 --- [ main] com.example.demo.CiaoMondoApplication : Starting CiaoMondoApplication on Asus-Mattia with PID 9572 (C:\Users\matti\eclipse-workspace\ciao-mondo\target\classes started by matti in C:\Users\matti\eclipse-workspace\ciao-mondo)
2019-06-11 11:09:33.091 INFO 9572 --- [ main] com.example.demo.CiaoMondoApplication : No active profile set, falling back to default profiles: default
2019-06-11 11:09:33.627 INFO 9572 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-06-11 11:09:33.644 INFO 9572 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 11ms. Found 0 repository interfaces.
2019-06-11 11:09:33.895 INFO 9572 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$bb774f16] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-06-11 11:09:34.107 INFO 9572 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-06-11 11:09:34.127 INFO 9572 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-06-11 11:09:34.127 INFO 9572 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.19]
2019-06-11 11:09:34.219 INFO 9572 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-06-11 11:09:34.219 INFO 9572 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1094 ms
2019-06-11 11:09:34.271 WARN 9572 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
2019-06-11 11:09:34.274 INFO 9572 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2019-06-11 11:09:34.284 INFO 9572 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-06-11 11:09:34.289 ERROR 9572 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
You have a data start dependency but didn't add the driver for H2 or you want to use another database then you have to add at least: url, username, password
If you don't want to use a database remove the starter from your maven or gradle project file.
You might have mentioned below dependency
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
So, Spring will look for datasource url in application.properties, so remove that or if you you want to work with jdbc add the properties in application.properties
spring.datasource.url = <jdbc-url>
spring.datasource.username = <db-username>
spring.datasource.password = <db-password>
spring.datasource.driverClassName = <db-driver>
If you don't use any datasource in your application you can put following annotation on your CiaoMondoApplication class
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
/*
* Hi Simon,
*
* Couple of questions, have you used the Spring Initializr to build the project or * have you done if from scratch?
*
* https://start.spring.io/
*
* Is a good place to start:
*
* Here is my basic app (to call a sendgrid api) but that does not matter.
*
*/
// Rest Application
package com.XXXXXXX.restapi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RestApiApplication{
public static void main(String[] args)
{
SpringApplication.run(RestApiApplication.class, args);
}
}
and that is all that is in my restapi.java
I then have a controller
sendgridcontroller.java
import java.io.IOException;
#RestController
#RequestMapping(sendGridController.BASE_URL)
public class sendGridController
{
public static final String BASE_URL = "/api/v1/feedbacks";
private final sendGridAPI sendGridAPIService;
public sendGridController(sendGridAPIImpl sendGridAPIService)
{
this.sendGridAPIService = sendGridAPIService;
}
#CrossOrigin
#PostMapping("/sendfeedback")
public ResponseEntity<Boolean> sendFeedback(#RequestParam(name="fullname")String fullName,
#RequestParam(name="subject")String subject,
#RequestParam(name="email") String emailAddr,
#RequestParam(name="message")String message )
{
Boolean bReturn = true;
System.out.println("fullName ="+fullName);
System.out.println("subject ="+subject);
System.out.println("email ="+emailAddr);
System.out.println("message ="+message);
try
{
sendGridAPIService.sendFeedbackEmail(fullName, subject, emailAddr, message);
}
catch(Exception e)
{
return new ResponseEntity<>(false,HttpStatus.BAD_GATEWAY);
}
return new ResponseEntity<>(bReturn, HttpStatus.OK);
}
}
This is in its own package
Next i created a services package with two files
an Interface sendGridApi.java
package com.ea_optimised.restapi.services;
import org.springframework.stereotype.Service;
import java.io.IOException;
public interface sendGridAPI
{
void sendFeedbackEmail(String fullNameme, String subject, String emailAddr, String message) throws IOException;
}
// .... and Finally, I have an implementation of the interface
package com.XXXXX.restapi.services;
import com.sendgrid.*;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.net.UnknownHostException;
import java.rmi.ServerException;
#Service
public class sendGridAPIImpl implements sendGridAPI
{
// API_KEY
private static final String SENDGRID_API_KEY = "My key went here";
#Override
public void sendFeedbackEmail(String fullNameme, String subject, String emailAddr, String message) throws IOException
{
Email from = new Email(emailAddr);
Email to = new Email("info#ea-optimised.co.uk");
// Email to = new Email("test#example.com");
Content content = new Content("text/plain", message);
Mail mail = new Mail(from, subject, to, content);
SendGrid sg = new SendGrid(SENDGRID_API_KEY);
Request request = new Request();
try
{
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
System.out.println("****\nSTATUS="+response.getStatusCode());
System.out.println("\n***Body :\n\n"+response.getBody());
System.out.println("***Headers:\n\n"+response.getHeaders());
}
catch ( UnknownHostException e )
{
System.out.println("***Unknown Host Exception:\n\n");
throw e;
}
catch (Exception ex)
{
System.out.println( "SendGrid Failed "+ex.getMessage());
try
{
throw ex;
}
catch (IOException e)
{
e.printStackTrace();
throw e;
}
}
}
}
Hope this helps
Finally are you using Gradle or Maven?

How do I configure this property with Spring Boot and an embedded Tomcat?

Do I configure properties like the connectionTimeout in the application.properties file or is the somewhere else to do it? I can't figure this out from Google.
Tomcat properties list
I found this Spring-Boot example, but it does not include a connectionTimeout property and when I set server.tomcat.connectionTimeout=60000 in my application.properties file I get an error.
Spring Boot 1.4 and later
As of Spring Boot 1.4 you can use the property server.connection-timeout. See Spring Boot's common application properties.
Spring Boot 1.3 and earlier
Provide a customized EmbeddedServletContainerFactory bean:
#Bean
public EmbeddedServletContainerFactory servletContainerFactory() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addConnectorCustomizers(connector ->
((AbstractProtocol) connector.getProtocolHandler()).setConnectionTimeout(10000));
// configure some more properties
return factory;
}
If you are not using Java 8 or don't want to use Lambda Expressions, add the TomcatConnectorCustomizer like this:
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
#Override
public void customize(Connector connector) {
((AbstractProtocol) connector.getProtocolHandler()).setConnectionTimeout(10000);
}
});
The setConnectionTimeout() method expects the timeout in milliseconds (see connectionTimeout in Apache Tomcat 8 Configuration Reference).
I prefer set of system properties before the server start:
/**
* Start SpringBoot server
*/
#SpringBootApplication(scanBasePackages= {"com.your.conf.package"})
//#ComponentScan(basePackages = "com.your.conf.package")
public class Application {
public static void main(String[] args) throws Exception {
System.setProperty("server.port","8132"));
System.setProperty("server.tomcat.max-threads","200");
System.setProperty("server.connection-timeout","60000");
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
After spring boot 2.x and later,
the implement method of the embeding tomcat has been changed.
refer to the code below.
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Configuration;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#Configuration
public class TomcatCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
#Autowired
private ContainerProperties containerProperties;
#Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(connector -> {
AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
protocol.setMaxKeepAliveRequests(10);
log.info("####################################################################################");
log.info("#");
log.info("# TomcatCustomizer");
log.info("#");
log.info("# custom maxKeepAliveRequests {}", protocol.getMaxKeepAliveRequests());
log.info("# origin keepalive timeout: {} ms", protocol.getKeepAliveTimeout());
log.info("# keepalive timeout: {} ms", protocol.getKeepAliveTimeout());
log.info("# connection timeout: {} ms", protocol.getConnectionTimeout());
log.info("# max connections: {}", protocol.getMaxConnections());
log.info("#");
log.info(
"####################################################################################");
});
}
}
It's actually supposed to be server.connection-timeout in your application.properties. Reference, I suggest you bookmark it.

SpringBoot WEB-INF not loaded

I have a spring boot application. Packaged as a war file, such that the contents are as follows
static
org - springframework - boot -loader - SpringClasses
META-INF
- MANIFEST.MF
- maven -my.group.id - my-artifact-id - pom.xml & pom.properties
WEB-INF
- lib (contains all jars)
- classes (my main application's classes)
- some other stuff
- web.xml
- main-servlet.xml
Where web.xml and main-servlet.xml are the configuration xml's
I tried, from the springBoot application doing as follows:
#EnableWebMvc
#EnableAutoConfiguration
#Configuration
#ImportResource({ "classpath:main-servlet.xml"})
public class FakeAppBooter {
public static void main(String args[]) {
SpringApplication.run(FakeAppBooter.class, args);
System.out.println("Test");
}
public DispatcherServlet mvcDispatcherServlet() {
XmlWebApplicationContext ctx = new XmlWebApplicationContext();
ctx.setConfigLocation("classpath:main-servlet.xml");
DispatcherServlet dispatcherServlet = new DispatcherServlet(ctx);
return dispatcherServlet;
}
#Bean
public ServletRegistrationBean mvcServletRegistrationBean() {
ServletRegistrationBean bean = new ServletRegistrationBean();
bean.setServlet(mvcDispatcherServlet());
ArrayList<String> list = new ArrayList<>();
list.add("/");
bean.setUrlMappings(list);
return bean;
}
}
However on startup I get :
Caused by: java.io.FileNotFoundException: class path resource [main-servlet.xml] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:329)
... 25 more
I need these to define the servlets for my application.
what should I do?
Solution for your Question:
While you are using SpringBoot Never care about your web.xml, Because SpringBoot itself will initialize your web Container through EmbeddedServletContainer preferably TomcatEmbeddedServletContainer. Hence ignore your web.xml configuration and it resolves your first question
You haven't placed your main-servlet.xml in proper classpath. Copy your main-servlet.xml and paste it in src folder of your project.
Change your code accordingly
import java.util.ArrayList;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
//Place your Imports Appropriately
/**
* #author Praveen
*
*/
#EnableWebMvc
#EnableAutoConfiguration(exclude=DataSourceAutoConfiguration.class)
#ImportResource({ "classpath:main-servlet.xml"})
#ComponentScan
public class FakeAppBooter {
private ApplicationContext ctx;
public static void main(String[] args) {
SpringApplication.run(FakeAppBooter.class, args);
System.out.println("Test>>>>");
}
public DispatcherServlet mvcDispatcherServlet() {
ctx = new ClassPathXmlApplicationContext();
((AbstractRefreshableConfigApplicationContext) ctx).setConfigLocation("classpath:main-servlet.xml");
DispatcherServlet dispatcherServlet = new DispatcherServlet();
return dispatcherServlet;
}
#Bean
public ServletRegistrationBean mvcServletRegistrationBean() {
ServletRegistrationBean bean = new ServletRegistrationBean();
bean.setServlet(mvcDispatcherServlet());
ArrayList<String> list = new ArrayList<>();
list.add("/");
bean.setUrlMappings(list);
return bean;
}
}
main-servlet.xml
I have kept the main-servlet.xml in a very simple manner.
main-servlet.xml file
Successful Log Below
Successful Log

Categories

Resources