How to change namingStrategy in springdoc? - java

I am using springdoc. It works flawlessly, except I am trying to change the default camelCase to PascalCase requests mapping.
I searched through the docs and cannot find a configuration to adjust property naming.
How can I change property naming when working with springdoc?

As #Debargha Roy mentioned in his answer, there is no clear way to do it via springdoc properties.
I propose my solution for Kotlin based on GitHub thread.
To get PascalCase or UpperCamelCase in Swagger, you can use ModelResolver:
#Bean
fun modelResolver(objectMapper: ObjectMapper): ModelResolver {
return ModelResolver(jacksonObjectMapper().registerModule(KotlinModule()).setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE))
}
It doesn't resolve the output response from Spring #RestController.
By default, Spring uses Jackson mapper to make responses follow UpperCamelCase, use this property spring.jackson.property-naming-strategy=UPPER_CAMEL_CASE in properties/yaml file.
After these 2 changes, both your Swagger and RestController will follow the UpperCamelCase style.
NOTE:
Beware, if you decided to reuse incoming objectMapper (see the snippet below), you may get duplicated payload with mixed camelCase:
#Bean
fun modelResolver(objectMapper: ObjectMapper): ModelResolver {
return ModelResolver(objectMapper.registerModule(KotlinModule()).setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE))
}

As far as I know, you can not do it. The reason being that there's no way to change the name of the request handler by using the Swagger annotations.
And lowerCamelCase for method/identifier names is promoted by the Java Naming Conventions and also by the Google Naming Convention.
You should still be able to compile and run the code if you don't follow the conventions. Other than that, I don't think there's an official way of changing the method name's case using Swagger directly.

#Dmytro Chasovskyi solution above also worked for me on SpringDoc.
I'm on java Spring though, all I had to do:
#Bean
public ModelResolver modelResolver(ObjectMapper objectMapper) {
return new ModelResolver(objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE));
}

Related

How to add converters when ApplicationConversionService.getSharedInstance() is no longer modifiable?

I'm in the process of upgrading spring boot from 2.4.2 to 2.5.6.
In our code we have been using ApplicationConversionService.getSharedInstance().addConverter() to add our custom converters. It puzzles me a bit that this is mentioned as a "New feature" rather than a breaking change for Spring boot 2.5.0-RC1, see the top mention here. https://github.com/spring-projects/spring-boot/releases?page=3
It was changed by this PR: https://github.com/spring-projects/spring-boot/issues/26088
How can we add the converters instead?
You need to provide the converter as a bean and annotate the bean definition with #ConfigurationPropertiesBinding. The simplest way to do so is probably to annotate the converter class with #Component and #ConfigurationPropertiesBinding.
See also this part of the reference documentation: https://docs.spring.io/spring-boot/docs/2.5.6/reference/htmlsingle/#features.external-config.typesafe-configuration-properties.conversion

Rest endpoint defined in annotation

I'm using a bunch of microservices in my project. These microservices all share one common endpoint that returns an object which has been parsed through XML.
Now I'd love to have some kind of default method defined within the Annotation like this:
#RestController
public #interface ComaModule {
Class<? extends Object> clazz();
#RequestMapping("/descriptor")
default ModuleDescriptor getDescriptor() {
ModuleXmlUnmarshaller moduleXmlUnmarshaller = new ModuleXmlUnmarshaller(clazz());
Optional<ModuleDescriptor> moduleDescriptorOptional = moduleXmlUnmarshaller.findModuleDescriptor();
return moduleDescriptorOptional.orElse(null);
}
}
That does not work since I am not able to have a method definition in my annotation. So the hard stuff is that I want to keep #RequestMapping("/descriptor") for this.
In fact I want some kind of aspect for every RestController I use. I read about AOP for Spring and Proxy but thought I might be able to achieve this with Annotations.
May be you can try adding annotation processor class, where you can write the code which have in your post and achieve what your goal.

Spring Boot YAML config and list

I have to integrate a list in a YAML config file in Spring Boot, and don't see how to proceed.
I already saw other questions related : Spring Boot yaml configuration for a list of strings
And have the same issue.
I applied the solution and worked around, and found the solution a little tricky.
Is there a way to make lists work with the #Value ?
And if not now, is it expected in future ?
Thanks a lot.
According to this documentation you can do a list in yaml.
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-yaml
YAML lists are represented as property keys with [index] dereferencers, for example this YAML:
my:
servers:
- dev.bar.com
- foo.bar.com
Would be transformed into these properties:
my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com
To bind to properties like that using the Spring DataBinder utilities (which is what #ConfigurationProperties does) you need to have a property in the target bean of type java.util.List (or Set) and you either need to provide a setter, or initialize it with a mutable value, e.g. this will bind to the properties above
#ConfigurationProperties(prefix="my")
public class Config {
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
return this.servers;
}
}
https://www.youtube.com/watch?v=d6Scea1JdMg&t=9s
Please refer to the above link. Maybe it helps, shown how to read different data types in application.yml in the Spring Boot.
There is a related GitHub thread: #Value annotation should be able to inject List from YAML properties. The issue has been closed, and according to a comment in a duplicate issue, they're not considering implementing the support now. It will be reopened once they decide to work on it.
Until then, you can go the way described in #mark's answer, using #ConfigurationProperties, also mentioned on GitHub.

Building custom java config annotations - similar to custom XML namespaces

We're building a framework on top of Spring & Spring MVC. Our framework is quite mature at this point - about 2 years old and is used widely within our organization. Our framework is very modular (much like spring itself is). There are various modules that can be used independently or together. When used together they provide many benefits to the end user. We have built a handful custom spring XML namespaces (NamespaceHandlers, BeanDefinitionParsers, etc). Each module provides their own which brings in its own set of XML configuration elements. This is all working great for us and has been a really big win for us.
What we'd like to do now is move away from XML-based configuration and into java config. My idea/thought is for each module to introduce a set of java config annotations that can be used (something similar to the #EnableCaching, #EnableMBeanExport annotations). My question is this - even if I create my annotations - how do I "wire" them in so that if they are present I can do "stuff"? This would be similar conceptually to the NamespaceHandlers & BeanDefinitionParsers. I can't find any documentation anywhere as to how to get started.
I've thought about creating some custom abstract base classes which do what I need them to do - but the problem is when it comes to the end user's application - they can only extend a single class. I need a flexible way for each module in my framework to expose its own custom configuration that end user applications can use, just like they use our XML namespace elements.
Here's a glimpse as to what we do in XML (not full application context file - just a blurb from it pertaining to our custom XML namespaces):
<atom-web:web/>
<atom-web:logging/>
<atom-web:security entitlementsProvider="XML" xmlRefreshInterval="${cache.refresh.interval.ms}"/>
<atom-profile:profile caching="IN_MEMORY" entryExpiryDelay="${cache.refresh.interval.ms}"/>
<atom-prefs:preferences backingStoreUrl="${pref.backingStore.url}"/>
<atom-content:content contentServerBaseUrl="${content.server.url}" contentServerFileUrl="${content.server.file.url}" site="${site.name}" contentTaskExecutor="contentTaskExecutor" snippetCaching="IN_MEMORY" cacheRefreshInterval="${cache.refresh.interval.ms}"/>
<bean id="contentTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" p:corePoolSize="3" p:maxPoolSize="20"/>
What I'm envisioning is some kind of set of annotations - something like this:
#EnableAtomWebApplication
#EnableAtomWebLogging
#EnableAtomWebSecurity(entitlementsProvider=EntitlementsProvider.XML, xmlRefreshDelay=120000)
#EnableAtomProfile(caching=CachingType.IN_MEMORY, expiryDelay=120000)
// Other annotations for rest of modules
#Configuration
public class ConfigurationClass {
// Rest of configuration in here
}
Any help here would be greatly appreciated. I'm not quite sure where to start and can't really find any documentation anywhere to help me get started.
So after thinking about this a bit I think I've found the correct starting point. I wanted to throw this out there for anyone who might be able to say "yeah thats the right place" or "no you aren't looking in the correct place".
Using my example above
#EnableAtomProfile(caching=CachingType.IN_MEMORY, expiryDelay=120000)
I would create an annotation for the #EnableAtomProfile annotation like this:
#Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
#Target(value={java.lang.annotation.ElementType.TYPE})
#Documented
#Import({AtomProfileBeanDefinitionRegistrar.class})
public #interface EnableAtomProfile {
CachingType caching() default CachingType.NONE;
long expiryDelay default 0;
}
The AtomProfileBeanDefinitionRegistrar class would implement org.springframework.context.annotation.ImportBeanDefinitionRegistrar and do any of the necessary stuff that I'm currently doing in my BeanDefinitionParser
You can have a BeanPostProcessor defined, which would basically:
inspect every single bean created
with reflection check if the object's class is annotated with #YourAnnotation
and if it is, then apply some custom logic - e.g. package the object into some other class or something
Reference:
Spring docs on BeanPostProcessors
source code for RequiredAnnotationBeanPostProcessor, which is a BeanPostProcessor which analyzes annotations

Conditionally creating beans in spring

Right now I'm exposing the service layer of my application using spring remoting's RMI/SOAP/JMS/Hessian/Burlap/HttpInvoker exporters. What I'd like is to allow the user to somehow define which of these remoting mechanisms they'd like enabled (rather than enabling all of them), then only create those exporter beans.
I was hoping that spring's application context xml's had support for putting in conditional blocks around portions of the xml. However, from what I've seen so far there's nothing in the standard spring distribution that allows you to do something like this.
Are there any other ways to achieve what I'm trying to do?
I am going to assume that you are looking to configure your application based on your environment, as in... for production I want to use this beans, in dev these other ...
As Ralph is saying, since Spring 3.1 you have profiles... But the key, is that you understand that you should put your environment based beans in different configuration files... so you could have something like dev-beans.xml, prod-beans.xml... Then in your main spring file, then you just invoke the appropriate one based on the environment that you are using... So profiles are only technique to do so... But you can also use other techniques, like have a system environmental variable, or pass a parameter in your build to decide which beans you want to use
You could realize this by using a Spring #Configuration bean, so you can construct your beans in java code. (see http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java)
#Configuration
public class AppConfig {
#Bean
public MyService myService() {
if ( userSettingIshessian ) {
return new HessianExporter();
}else {
return new BurlapExporter();
}
}
}
Of course you need to get the user setting from somewhere, a system parameter would be easy, or config file, or something else.
Spring 3.1 has the concept of Profiles. My you can use them.

Categories