How to know which message converter is used by spring boot? - spring-boot

For some reason I decided to change to another message converter, my code is below
#Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = new FastJsonHttpMessageConverter();
return new HttpMessageConverters(additional);
}
Now I'd like to know how to check whether this custom converter is in effect? I tried to access /beans but only got this
{
bean: "customConverters",
scope: "singleton",
type: "org.springframework.boot.autoconfigure.web.HttpMessageConverters",
resource: "com.foo.BarApplication",
dependencies: [ ]
}
So does exist some manner to know which message converter is used by spring boot?

Because I'm not very sure if my custom converter works, so I have to track source code. I cloned spring framework then attached it in eclipse, then debug step by step and found something.
In AbstractMessageConverterMethodProcessor.writeWithMessageConverters
for (HttpMessageConverter<?> messageConverter : this.messageConverters)
when watch this.messageConverters got below output
[org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter#1eb0d2e8, com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter#2026476b, org.springframework.http.converter.ByteArrayHttpMessageConverter#3287cbc7, org.springframework.http.converter.StringHttpMessageConverter#2c19dd3, org.springframework.http.converter.ResourceHttpMessageConverter#1afe28f1, org.springframework.http.converter.xml.SourceHttpMessageConverter#87129da, org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter#4a412e0, org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#a8528a2, org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter#61d720a3]
and actually it used com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter#2026476b

Only injected dependencies are shown in the dependencies array. If you do something like
#Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
return new FastJsonHttpMessageConverter();
}
#Bean
#Autowired
public HttpMessageConverters convertersToBeUsed(FastJsonHttpMessageConverter converter) {
return new HttpMessageConverters(converter);
}
you will see the FastJsonHttpMessageConverter in the list.
If you want to see all registered converters, look for HttpMessageConvertersAutoConfiguration in the bean list. It should look similar to this:
{
bean: "org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration",
scope: "singleton",
type: "org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration$$EnhancerBySpringCGLIB$$9e15b021",
resource: "null",
dependencies: [
"fastJsonHttpMessageConverter",
"stringHttpMessageConverter"
]
}

Related

how to inject an array of Beans in spring boot?

In Spring, we can inject a bean like bellowing code:
#Bean
public AspectJExpressionPointcutAdvisor configurabledvisor() {
System.out.println("configurabledvisor");
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(pointcut);
advisor.setAdvice(new LogAroundAdvice());
return advisor;
}
In some situation, it is needed that an array of beans should be injected, the pseudo code like that:
#Bean[]
public AspectJExpressionPointcutAdvisor[] configurabledvisorArray() {
System.out.println("configurabledvisor");
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(pointcut);
advisor.setAdvice(new LogAroundAdvice());
AspectJExpressionPointcutAdvisor advisor1 = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(pointcut2);
advisor.setAdvice(new AnotherAdvice());
return new AspectJExpressionPointcutAdvisor[]{advisor, advisor1};
}
Any help would be appreciated, thanks in advance.
Demo code address is: https://github.com/sluk3r/inject-multipleBeans/tree/main
You just need to remove the []
#Bean
public AspectJExpressionPointcutAdvisor[] configurabledvisorArray() {
...
}
then you can inject (using autowire, constructor, setter, ...) your bean everywhere
#Autowire
private AspectJExpressionPointcutAdvisor[] configurabledvisorArray;
or as a dependency of another bean
#Bean
String testBean(AspectJExpressionPointcutAdvisor[] configurabledvisorArray){
...
}

axon 4 snapshot in demand

I work with spring boot and axon example, i implement the snapshot feature, with the below code is working fine, after 3 events i found the data in the table snapshot_event_entry in the database
#Configuration
#AutoConfigureAfter(value = { AxonAutoConfiguration.class })
public class AxonConfig {
#Bean
public SnapshotTriggerDefinition catalogSnapshotTrigger(Snapshotter snapshotter) {
return new EventCountSnapshotTriggerDefinition(snapshotter, 3);
}
}
#Aggregate(snapshotTriggerDefinition = "catalogSnapshotTrigger")
public class CatalogAggregate { }
My question, is there a method to do a snapshot in demand? That means i want to implement an api to do the snapshot, not automatically after 3 events
there is nothing already in place.
One way to implement what you need is to create a dedicated Command, eg PerformShapshotCmd, that will carry the aggregateId information, and a #CommandHandler into your Aggregate. You could then let Spring autowire the Snapshotter instance bean, and call for the scheduleSnapshot(Class<?> aggregateType, String aggregateIdentifier) method.
Below some code snippet that could guide you.
data class PerformShapshotCmd(#TargetAggregateIdentifier val id: String)
#CommandHandler
public void handle(PerformShapshotCmd cmd, Snapshotter snapshotter) {
logger.debug("handling {}", cmd);
snapshotter.scheduleSnapshot(this.getClass(), cmd.getId());
}
You should also define one Bean of type Snapshotter into your config
#Bean
public SpringAggregateSnapshotterFactoryBean snapshotter() {
SpringAggregateSnapshotterFactoryBean springAggregateSnapshotterFactoryBean = new SpringAggregateSnapshotterFactoryBean();
//Setting async executors
springAggregateSnapshotterFactoryBean.setExecutor(Executors.newSingleThreadExecutor());
return springAggregateSnapshotterFactoryBean;
}
Please note that the first argument of your commandHandler needs to be the command, otherwise the framework will complain with an exception at startup time.

Springdoc GroupedOpenApi not following global parameters set with OperationCustomizer

When using GroupedOpenApi to define an API group, the common set of parameters that are added to every endpoint is not present in the parameters list.
Below are the respective codes
#Bean
public GroupedOpenApi v1Apis() {
return GroupedOpenApi.builder().group("v1 APIs")
// hide all v2 APIs
.pathsToExclude("/api/v2/**", "/v2/**")
// show all v1 APIs
.pathsToMatch("/api/v1/**", "/v1/**")
.build();
}
And the class to add the Standard Headers to all the endpoints
#Component
public class GlobalHeaderAdder implements OperationCustomizer {
#Override
public Operation customize(Operation operation, HandlerMethod handlerMethod) {
operation.addParametersItem(new Parameter().$ref("#/components/parameters/ClientID"));
operation.addSecurityItem(new SecurityRequirement().addList("Authorization"));
List<Parameter> parameterList = operation.getParameters();
if (parameterList!=null && !parameterList.isEmpty()) {
Collections.rotate(parameterList, 1);
}
return operation;
}
}
Actual Output
Expected Output
Workaround
Adding the paths to be included/excluded in the application properties file solves the error. But something at the code level will be much appreciated.
Attach the required OperationCustomizerobject while building the Api Group.
#Bean
public GroupedOpenApi v1Apis(GlobalHeaderAdder globalHeaderAdder) {
return GroupedOpenApi.builder().group("v1 APIs")
// hide all v2 APIs
.pathsToExclude("/api/v2/**", "/v2/**")
// show all v1 APIs
.pathsToMatch("/api/v1/**", "/v1/**")
.addOperationCustomizer(globalHeaderAdded)
.build();
}
Edit: Answer updated with reference to #Value not providing values from application properties Spring Boot
Alternative to add and load OperationCustomizer in the case you declare yours open api groups by properties springdoc.group-configs[0].group= instead definition by Java code in a Spring Configuration GroupedOpenApi.builder().
#Bean
public Map<String, GroupedOpenApi> configureGroupedsOpenApi(Map<String, GroupedOpenApi> groupedsOpenApi, OperationCustomizer operationCustomizer) {
groupedsOpenApi.forEach((id, groupedOpenApi) -> groupedOpenApi.getOperationCustomizers()
.add(operationCustomizer));
return groupedsOpenApi;
}

jar package is not behaving as expected

I have made a code using spring boot and itextpdf 5, actually I am trying to do something like this example
https://github.com/aboullaite/SpringBoot-Excel-Csv
my code is working fine when I run it in my STS IDE, but it shows error as error resolving template when I create jar file and run it, can anyone please help
Edit:- I am using thymeleaf for html view
Code
this is my webconfig class
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.defaultContentType(MediaType.APPLICATION_JSON)
.favorPathExtension(true).ignoreAcceptHeader(true);
}
#Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
// Define all possible view resolvers
List<ViewResolver> resolvers = new ArrayList<>();
resolvers.add(csvViewResolver());
resolvers.add(excelViewResolver());
resolvers.add(pdfViewResolver());
resolver.setViewResolvers(resolvers);
return resolver;
}
/*
* Configure View resolver to provide XLS output using Apache POI library to
* generate XLS output for an object content
*/
#Bean
public ViewResolver excelViewResolver() {
return new ExcelViewResolver();
}
/*
* Configure View resolver to provide Csv output using Super Csv library to
* generate Csv output for an object content
*/
#Bean
public ViewResolver csvViewResolver() {
return new CsvViewResolver();
}
/*
* Configure View resolver to provide Pdf output using iText library to
* generate pdf output for an object content
*/
#Bean
public ViewResolver pdfViewResolver() {
return new PdfViewResolver();
}
}
and here are my controller methods
#GetMapping( "/download")
public String download(Model model) {
model.addAttribute("cards", new StudentsDto());
return "getReportCard";
}
#PostMapping("/download")
public String postReportCard(#ModelAttribute("cards") StudentsDto cards, Model model){
List<Students> sList=studentService.searchByClassSectionBySession(cards.getClassSection(), cards.getSession());
model.addAttribute("studentsList", sList);
return "";
}
My question is , If everythinbg is working fine on running code as spring boot application through my STS IDE then why the jar I have created is not showing pdf views ?
I have created jars from my sts ide, i did maven clean and then i created jar using maven install
Solved
Was a stupid mistake, I don't kn how but in my template folder I changed the name of file getReportCard.html as getReportCArd.html.
Was a silly mistake and I checked upon each and every possible configuration. :-)

Spring Batch - How to set RunIdIncrementer globally using JavaConfig

im developing a Project using Spring Batch and JavaConfig (no XML).
I am creating Jobs using an Autowired jobBuilderFactory.
is it somehow possible to set the Incrementer for the Factory globally ?
return jobBuilderFactory.get("jobName").incrementer(new RunIdIncrementer()).start(stepOne()).next(lastStep()).build();
sorry if this is a dump question but i am new to Spring Batch and did not find a working solution.
With XML config you would use bean definition inheritance, but you said you don't use XML.
Since there is no equivalent of XML bean definition inheritance with Java config (See details here: https://stackoverflow.com/a/23266686/5019386), you can create the RunIdIncrementer globally in your config and use it in job definitions:
public JobParametersIncrementer jobParametersIncrementer() {
return new RunIdIncrementer();
}
public JobBuilder getJobBuilder(String jobName) {
return jobBuilderFactory.get(jobName)
.incrementer(jobParametersIncrementer());
}
#Bean
public Job job1() {
return getJobBuilder("job1")
.start(step())
.build();
}
#Bean
public Job job2() {
return getJobBuilder("job2")
.start(step())
.build();
}
But again and as said in comments, you will end up having run.id values that are not consecutive for each job.

Resources