springdoc-openapi generate openapi yaml on build without server - spring

I have a Spring boot Gradle project and I want to get it's OpenAPI spec YAML file.
As I understand the official swagger-core does not support Spring boot projects, thus I found springdoc-openapi (https://github.com/springdoc/springdoc-openapi-gradle-plugin).
It seems that in order to get the YAML/JSON files, when running the generateOpenApiDocs task, the springdoc library sets up a server with some endpoints (/v3/api-docs) to download the files.
I'm using the default configuration, and for some reason I keep getting the following error:
Execution failed for task 'generateOpenApiDocs'.
Unable to connect to http://localhost:8080/v3/api-docs waited for 30 seconds
It seems that for some reason it does not set up the server. How can I fix it?
Is it possible to skip the server part? Can I configure springdoc to simply generate files on build?

If you are deploying REST APIs with spring-boot, you are relying on a servlet container.
The necessry metadata for the OpenAPI spec are only available by spring framework on runtime, which explains the choice of generation at runtime.
You can define any embeded servlet container, during your integration tests to generate the OpenAPI Spec.

This is how I resolved the issue
Specify the path
In your properties file enter:
springdoc:
api-docs:
path: /{your path}
Configure the plugin
In your build.gradle file enter:
openApi {
apiDocsUrl.set("http://localhost:{your port}/your path)
}

This happens because sometimes embedded server took sometime to start and it has 30 sec default setting. Please add the below properties in your openAPI block and it will work fine for you. Please see the below sample:
openApi {
apiDocsUrl.set("http://localhost:9090/v3/api-docs.yaml")
outputDir.set(file("Your Directory path"))
outputFileName.set("openapi.yaml")
forkProperties.set("-Dserver.port=9090")
waitTimeInSeconds.set(60)
}

You need to add the dependency below, an updated version may exist depending on when you're seeing this - intellij would tell you and help upgrade:
implementation('org.springdoc:springdoc-openapi-ui:1.6.11')
Then add the line below to your application.properties file:
springdoc.api-docs.path=/api-docs
Perhaps also get rid of the plugin, it's not necessary as long as you have the above dependency. I got rid of mine and things work fine.
After the dependency is resolved, run the app normally with intellij run buttons or the commandline.
With the app running, visit http://localhost:8080/swagger-ui/index.html - assuming your app is running on port 8080. If not, use the right port accordingly.
Also, you can check out https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/10 and https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/10#issuecomment-594010078 - those were helpful when I faced the same issue, showed me part of what to do.

Related

How can I tell Spring Boot to place some of the classes at the root of the jar instead of BOOT-INF?

I'm trying to set a custom log Handler in my Spring Boot (version 2.6.3) application. The result is a ClassNotFound as described in this other question
Can't override java.util.logging.LogManager in a Spring Boot web application: Getting java.lang.ClassNotFoundException on already loaded class
Based on the answer to that question, it seems I need my Handler and all its dependencies to be placed into the root of the executable jar.
Is there a direct way to accomplish this during the Maven build, i.e. not by extracting and repackaging the jar myself post-build?
This issue is a result of BOOT-INF fat jar structure introduced by Spring Boot 1.4.
There is currently no straightforward solution, and it appears some of the Spring Boot maintainers do not agree there is a problem, so it could be a long time before the situation changes:
Issue #6626: Make it easier to package certain content in the root of a fat jar
Issue #12659: Starting executable war with -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager produces a ClassNotFoundException
WORKAROUND #1
I had to do two things to get my application working again with a custom log handler. 1) use Maven Shade to package up the log handler with all its dependencies, and 2) launch the app with using the PropertiesLauncher class in the command line instead of using java -jar:
java -cp executable.jar:logger-shaded.jar -Dloader.main=mypackage.myapp org.springframework.boot.loader.PropertiesLauncher
The executable.jar, logger-shaded.jar, and mypackage.myapp are placeholders specific to my project, so adjust accordingly.
WORKAROUND #2
If the handler is loaded from code in a config class or from main() instead of being specified in the file loaded via java.util.logging.config.file, as discussed in the comments to the answer in this other question, then everything works as expected. I actually prefer this over Workaround #1 as it results in a smaller deployment, but it does require writing a few more lines of code.

url after spring maven deployment

I have a basic question about deployment but I can't seem to find an answer on google...
I am working on a jakarta project and it's the first time I do the deployment.
Since I am using Spring-boot maven, I know there is an embedded tomcat that will launch with the jar.
My issue is, I don't know what url to use to check my project is working...
Before, I used the address http://localhost:9091/contextPath/endpoint, but now, I only get a whiteScreen...
So my question is, what url should I use ? Also, is there something else to do after packaging ?
Thank you for your answers.
EDIT:
Alright, so I tried actuator but that didn't help me...
With /actuator/mappings, I could see that my endpoints are correctly configured but when I use the executable jar, http://localhost:9091/contextPath/endpoint odes not work while it does if I compile with my IDE...
I don't know what url to connect to just to see the index... I'm using a very basic spring framework (boot and mvc) and my IDE is intellij community if this helps anyone
EDIT 2:
I tried to deploy the app on a local Tomcat9 to see if something would change but the connexion is reinitialized everytime I try to deploy a war using the manager, and there was no trace of error in the logs.
I tried using ./mvnw and it did work, endpoint and all, but it implies working with IDE environment
I tried using java (openjdk 13) and it compiled, but i couldn"t acces my own endpoint. I could still access the actuator endpoints so i don't know what to make of it.
Should the url be different depending on whether we are using IDE environment or just the jar?
EDIT 3:
Ok, I think have a lead but I have no idea how to resolve this:
when I began the web part of the application, I created a WEB-INF folder where I put all my jsp. My js and css files were in the resources/static folder. I tried once to put the jsp in the resources folder but it didn't work so I didn't push too hard.
Now, when I unzip the jar, i find my css and js files, but not my jsp.
When I unzip my war file, I have everything, but when I try to deploy it on a separate tomcat server, the connexion resets and I don't know why because nothing is written in the logs.
The issue then becomes:
Right now, I have
└──src
└──main
├──java
├──resources
| ├──static
| | ├──css
| | └──js
| └──template
└──webapp
└──WEB-INF
└──classes
└──jsp
What is the standard tree in intellij with jsp ?
By default Spring Boot apps are on port 8080.
Can you try http://localhost:8080?
Port can be changed in application.properties (or application.yml, application-profile.properties etc.) via server.port property (e.g. server.port=8888).
Ok, I managed to make it work.
I'm going to describe here everything of note that I encountered.
First, when I called my app to the usual url, there was no response (whiteLabel).
I added test logs and i found that I indeed called m controller.
I unzipped the jar and war i produced and came to the conclusion that the issue was architectural. I couldn't use jar, I had to use the war file.
I tried to deploy on a local tomcat server using the manager, but it always resetted the connection, so I took the manual approach - copy pasting the war file in the webapp directory.
Finally, the web pages were accessible in the browser.
Thank you for all the tips given during my research!
`http://endpoint:{PORT}/actuator/health` or `http://endpoint:{PORT}/actuator/status`
it should help but it must require spring-boot-actuator as a dependency in your pom/gradle file.

How to specify Log4j2 configuration file in spring boot application

I am using log4j2 in my spring boot application. This works in all respects re: excluding slf4j, including log4j2, etc.
But when the application deploys I need to customize the file for each target host. I have created an ansible role that does this. Ultimately I end up with a log4j2.xml file deployed in another directory e.g. /prod/produsrX/data/log4j2.xml.
I am using the spring-boot-maven-plugin "repackage" goal to generate an executable jar file. It doesn't seem like that should matter but it is a data point in the problem.
This was supposed to be the easiest part of the project. Always before I have just been able to set -Dlog4j.configurationFile - advice which is echoed on about 3,000 web pages and DOES NOT WORK in Spring Boot 2.1.3.
The most useful info I've found is this question. It talks about using -Dlogging.config because logging must be initialized before other properties are read. Unfortunately that didn't help either.
I did find one example that suggested specifying the above directory in a -classpath parameter to java. But that didn't help either.
Does anyone know how to get a spring boot application to read the log4j2.xml file?
The property actually has to be put into the application context (e.g. application.yml). Using a -D property does not work!
logging:
config: /prod/produsrX/data/log4j2.xml #fully qualified name to your log4j.xml

Expanding Properties in Gradle Breaks LDAP Config

Summary: I'm trying to access project properties (such as the version) in Java, and everywhere I've read says I need to expand properties in my build.gradle file. That's all fine and dandy, but I'm using LDAP and am configuring it in my properties file. Whenever I try to expand properties, I get the LDAP error 49 52e (Invalid Credentials), so it seems that whatever Gradle does to process the properties warps the LDAP properties so they are no longer usable.
Project Info:
I've outlined what I've thought to be the applicable project info below. If there are further details needed to determine the issue, comment and I'll add them.
Language:
Groovy 2.4
Java 8
Framework:
Spring Boot version: 1.3.1.RELEASE with starter POM
spring-boot-starter-security included
spring-security-ldap included
Build Tool: Gradle
Version 2.3
Spring Boot Gradle Plugin 1.3.1.RELEASE
Applied Plugins:
groovy
spring-boot
Build Info: I've tried a few different configurations in my build.gradle file to acess the version, but the moment I add the 'processResources' block, I can no longer access LDAP when running the application. The application runs and authenticates just fine without a 'processResources' block, but as soon as I add it, it will run, but I can't access anything due to LDAP complaining about invalid credentials. I tried 3 different expand configurations and all behaved this way.
Build Config Attempt 1:
processResources {
expand(project.properties)
}
Build Config Attempt 2:
processResources {
filesMatching('**/*.properties') { expand(project.properties) }
}
At this point it occurred to me that I'm configuring my LDAP login in a properties file, so maybe the solution was to avoid properties files altogether. I found out that you can supposedly just expand the properties you need, so I tried the following.
Build Config Attempt 3:
processResources {
expand projectVersion: project.version
}
As stated before, all of the above attempts failed and I still got LDAP authentication errors for each of them. A build.gradle file without a 'procesResources' block seems to be the only way to keep LDAP happy.
Properties Info: As stated before, I configured LDAP information in my properties files. Below are the relevant properties.
application.properties
spring.profiles.active=localdev
ldap.securitygroup=DEV
logout.path=
host.securePort=
As you can see, I'm using a localdev profile, so I've included the applicable properties from it below. Since it included sensitive information, I've only specified the property names and not their values. I've used a star (*) to indicate that there was a non-empty value provided. (in the above application.properties file the values were indeed empty for a couple of the properties listed):
application-localdev.properties
host.securePort=*
ldap.username=*
ldap.password=*
ldap.base=DC=*,DC=*,DC=*
ldap.roleSearchBase=OU=*,DC=*,DC=*,DC=*
ldap.defaultUrl=ldap://*
ldap.urls=ldap://* ldap://*
The properties didn't change at all, it just all worked without the processResources block in the build.gradle file, and then didn't when I added any of those 3 versions of it.
Any assistance to help figure this help would be greatly appreciated, and if any further information is needed, let me know and I'll update this.
So a co-worker gave me a great tip and said I could check the properties in the JAR file to see if there were different from what was originally specified.
Long story short, when I don't have a processResources block in the build.gradle file, the properties don't change and everything's happy. However, when processResources is added, ESCAPE CHARACTERS ARE REMOVED, causing the username to change, since I had an escape character in it.
The workaround I'm now using is to double up on the escape characters, which seems like a hack to me, so if there's a better way to configure this, please reply!

How to run a project containg drools in Tomcat7?

I have created a Dynamic web project which also uses drools for providing some functionality. When i put the WAR file in Tomcat7 and the server, the drools part does not work.
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
After this line which is first line relating to drools, nothing happens.
Is some configuration required to run my project containing drools 5.5.0 Final in the Tomcat7.
Please help me. I am badly stuck and I am new to drools.
You'll have to add some facts to the working memory and execute(fire) the rules. Check out these examples on GitHub
P.S. Probably not related to Tomcat in any way. Might be worth while to try getting the rules executed from command line app first.
You need to check all the dependencies that are added to your web application (WEB-INF/lib) make sure that drools has all the required deps there, because if not it will not be able to create the knowledge builder. Most of the time if it is failing is because that you forgot to add the deps in the web app.
The following project in GitHub is a web application, containing some REST-style endpoints for validating IBANs. It uses Drools 5.5 to perform that evaluation.
https://github.com/gratiartis/sctrcd-payment-validation-web/
It generates a .war which can be loaded into Tomcat, and could be a useful starting point. The knowledge base is wrapped within a Spring service:
https://github.com/gratiartis/sctrcd-payment-validation-web/blob/master/src/main/java/com/sctrcd/payments/validation/RuleBasedIbanValidator.java
Following through how that creates a knowledge base and session might help you see where your code is going wrong.
As a bonus, you can run it up in Tomcat using "mvn tomcat7:run" to test it out immediately.

Resources