How to generate openapi client from uri in Gradle - kotlin

I'm probably trying to do something strange, since this doesn't seem like a common question (or maybe I'm asking it all wrong). I was expecting this to be straightforward.
Basically, what I am looking for is a way to do the same as the following, except by using the gradle openapi-generator plugin:
openapi-generator generate -i www.example.com/openapi-doc -g spring
What I have tried is the following (and the associated errors):
inputSpec.set("www.example.com/openapi-doc") --> Cannot convert URL {} to a file
inputSpec.set(URL("www.example.com/openapi-doc").readText()) --> specified for property 'inputSpec' does not exist
The actual code looks something like this:
tasks.register<GenerateTask>("generateClient") {
validateSpec
generatorName.set("spring")
library.set("spring-cloud")
// inputSpec.set("$openapiSpecDir/client/openapi.json") <-- *I am currently using a file, which I don't want to do*
inputSpec.set("https://www.example.com/openapi-doc")
outputDir.set(generatedClientDir)
apiPackage.set("org.example.api")
modelPackage.set("org.example.model")
skipOverwrite.set(false)
templateDir.set("$rootDir/src/main/resources/openapi/templates/client")
configOptions.put("java8", "false")
configOptions.put("serializationLibrary", "jackson")
configOptions.put("dateLibrary", "java8")
}

Assuming you're using the OpenAPI Generator Gradle Plugin, at the time of writing this answer, getting the inputSpec from a URL is not supported. However, for Maven this has been implemented (Issue #2241 closed with PR #3826), so chances are good to have it implemented with a feature request that gets the Gradle plugin on par with its Maven counterpart.
That being said, you may want to look into Gradle Download Task. Gradle Download Task is a plugin that let's you download files from a URL. The downloaded file can be used to feed it into the OpenAPI generator.

Related

Micronaut Kotlin: Rest Controllers not working

I'm creating a simple application with 2 Rest Controllers with Kotlin. However, for every endpoint
the error is
{"message":"Not Found","_links":{"self":{"href":"
My inferences till now, for which I have searched for solutions and they didn't worked.
1.The generated folders are also empty. Might be an issue
As I have tried both IDE and command line. So, ruling out any issue from Idea
Tried to add a Java Controller in the project, but that also didn't run
Tried to use Micronaut annotations along with Spring Web annotations, didn't worked.
Is there anything else that I can change to make it work?
Ideally I would want to make it work with Kotlin and not Java.
Environment:
IDE - IntelliJ Idea 2020.2 Ultimate
Build - tried both Maven and Gradle, command line and IDE
EnableAnnotations: Done
Delegate Gradle Runner: Done
JDK: 11 ( but set as 8 in build file)
Update1 - Got few things working
Got the base code from Micronaut Launcher site
My Sample code
#RestController
#Validated
#RequestMapping("/hello")
open class UserController {
#Get("/echo")
fun echo():String{
return "hello"+ System.currentTimeMillis()
}
}
AOP is not working and thus had to use #Validated and open. The build.gradle has allOpen plugin.
#GetMapping should work as per https://micronaut-projects.github.io/micronaut-spring/latest/guide/#springMvc
I had to use Micronaut's #Get to make it working
Please help in fixing these 2 issues.

IntelliJ run vs running a jar, with a Springboot Kotlin, Multi module Gradle project with Social Oauth2

TL;DR: Why does everything run fine when started via IntelliJ, and why is it broken when call java -jar app.jar. And how do I fix this?
Alright, I have some issues with a backend I am trying to dockerize. I have an application created with Spring Boot (1.4.2.RELEASE) following the Spring Oauth (2.0.12.RELEASE) guide on their page. I follow the Gradle version, since I prefer Gradle over Maven. Also I am using Kotlin instead of Java. Everything is fine, I start via IntelliJ my backend with static front end, I can login via Facebook (and Google and Github), I receive a nice Principal witch holds al the information I need, and I can modify Spring Security to authorize and permit endpoints. So far so good.
Now for the bad part, when I run either ./gradlew clean build app:bootrun or ./gradlew clean build app:jar and run the jar via java -jar (like I will do in my Docker container), my backend comes up. My static front end pops up. Now I want to login via Facebook, I end up on the Facebook login page, I enter my credentials, and... nothing!
I end up back on my homepage, not logged in, no log messages that mean anything to me, just silence. The last thing I see in the log is:Getting user info from: https://graph.facebook.com/me
This Url will give me in my browser:
{
"error": {
"message": "An active access token must be used to query information about the current user.",
"type": "OAuthException",
"code": 2500,
"fbtrace_id": "GV/58H5f4fJ"
}
}
When going to this URL via an IntelliJ start, it will give me credential details. Obviously something is going wrong, but I have no clue what. Especially since a run from IntelliJ works fine. There is some difference between how the jar is started, and how IntelliJ's run config works, but I have no clue where to search for what. I could post trace logging, or all my Gradle files, but perhaps thats too much info to put in 1 question. I will defenitly update this question if someone needs some more details :)
The structure outline of this project is as follows:
root:
- api: is going to be opensourced later, contains rest definitions and DTOs.
- core: contains the meat. Also here is included in the gradle file
spring-boot-starter, -web, -security, spring-security-oauth2, and some jackson stuff.
- rest: contains versioned rest service implementations.
- app: contains angular webjars amongst others, the front end, and
my `#SpringBootApplication`, `#EnableOAuth2Client`
and the impl of `WebSecurityConfigurerAdapter`.
Why does everything run fine when started via IntelliJ, and why is it broken using bootRun or the jar artefact. And how do I fix this?
I found it, the problem was not Multi module Graldle, Spring boot, or Oauth2 related. In fact it was due to a src set config of Gradle, where Java was supposed to be in a Java src set folder, and Kotlin in a Java src set folder:
sourceSets {
main.java.srcDirs += 'src/main/java'
main.kotlin.srcDirs += 'src/main/kotlin'
}
As Will Humphreys stated in his comment above, IntelliJ takes all source sets, and runs the app. However, when building the jar via Gradle, these source sets are stricter. I had a Java file in my Kotlin src set, which is no problem for IntelliJ. But the jar created by Gradle takes into account the source sets as defined in the build.gralde file, which are stricter.
I found my missing bean issue with the code below:
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
The Bean I missed was called AuthenticationController, which is a #RestController, and kinda crucial for my authentication code.

Kotlin - Error: Could not find or load main class _DefaultPackage

I followed the Kotlin tutorial for eclipse here : Getting Started With Eclipse Luna
However, I'm running into this error:
Error: Could not find or load main class _DefaultPackage
Anyone who knows to get around this?
This was a severe bug (KT-10221) in automatic generation of Launch Configuration in plugin version 0.4.0. It was fixed in 0.5.0 so the recommendend way to workaround is to update plugin.
The source of the problem was that the plugin used an old pattern for generating name of the class for main function that had been abandoned by Kotlin compiler.
It's possible to workaround it by editing launch configuration (Eclipse Menu -> Run -> Run Configurations...) by hand and changing Main class field in Java Application group. If the file is named hello.kt with no package directive, as it is described in tutorial, than corrected string should be HelloKt.
If file has name other.kt with package my.tutorial than the Main Class should contain my.tutorial.HelloKt. You can read more about it in the section Package-Level Functions of Calling Kotlin From Java page.
I have been getting the same issue. And after putting the right compiler output path, it got resolved.
Go to Project -> Project Compiler output :
In the text box, fill this:
[Absolute Path]/{Project Name}/out
In my case I was having this problem while trying to run the program using the Application Gradle plugin. The problem was in the mainClassName property using single quotes instead of double ones
This didn't work:
mainClassName = 'demo.HelloWorldKt'
With double quotes, it works:
mainClassName = "demo.HelloWorldKt"
For me it worked after I installed the correct JDK. I first had JDK 11 but the tutorial I did was with JDK 8 so after I installed this and set it in the "installed JREs" options it found the main class without having any "mainClassName" or any other option in the build.gradle file.
For me, it worked in a fresh eclipse workspace. Possibly, the Kotlin eclipse plugin is not playing well with other plugins (in my case, PyDev).
I'm creating a Kotlin Application with JavaFX and I had this issue until I went to:
Run > Run Configurations > Java Application > Common
I unticked "Allocate console" and it fixed the issue.

Apache CXF + JavaFX No conduit initiator was found for the namespace

I'm triying to run a JavaFX Rest client using CXF. A very simple test. When I try to get an URL I get the org.apache.cxf.BusException: No conduit initiator was found for the namespace http://cxf.apache.org/transports/http. I took a look at some related questions here, but no luck. Any help would be appreciated.
Then only maven dependency I added was cxf-rt-rs-client 3.1.0
The code is:
WebClient client = WebClient.create("http://www.stackoverflow.com");
client.type("text/html").accept("text/html");
System.out.println(client.get());
Stacktrace:
Caused by: org.apache.cxf.BusException: No conduit initiator was found for the namespace http://cxf.apache.org/transports/http.
at org.apache.cxf.bus.managers.ConduitInitiatorManagerImpl.getConduitInitiator(ConduitInitiatorManagerImpl.java:110)
at org.apache.cxf.endpoint.AbstractConduitSelector.getSelectedConduit(AbstractConduitSelector.java:104)
at org.apache.cxf.endpoint.UpfrontConduitSelector.selectConduit(UpfrontConduitSelector.java:77)
at org.apache.cxf.message.ExchangeImpl.getConduit(ExchangeImpl.java:159)
at org.apache.cxf.interceptor.MessageSenderInterceptor.getConduit(MessageSenderInterceptor.java:71)
at org.apache.cxf.interceptor.MessageSenderInterceptor.handleMessage(MessageSenderInterceptor.java:46)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
at org.apache.cxf.jaxrs.client.AbstractClient.doRunInterceptorChain(AbstractClient.java:624)
at org.apache.cxf.jaxrs.client.WebClient.doChainedInvocation(WebClient.java:1100)
The shading overwrites bus-extension.txt file. Programmatically your can fix it by initializing it.
void initializeCxf() {
final Bus defaultBus = BusFactory.getDefaultBus();
final ConduitInitiatorManager extension = defaultBus.getExtension(ConduitInitiatorManager.class);
extension.registerConduitInitiator("http://cxf.apache.org/transports/http", new HTTPTransportFactory());
}
Based on the comment by #hba you can also try following in case the above does not work
extension.registerConduitInitiator("http://cxf.apache.org/transports/http", new HTTPTransportFactory(defaultBus));
You are fine with your Maven dependencies.
Client construction looks a bit off per CXF 3.x guides, wherein JAX-RS 2.0 is supported.
See AX-RS 2.0 Client API.
Try this code:
WebTarget target = ClientBuilder.newClient().target("http://stackoverflow.com/");
Response response = target.request().get();
System.out.println(response.getEntity().getClass().getName());
Using this code, you will learn the response entity is an input stream .. a sequence of characters being the HTML content of the StackOverflow home page.
If you're feeling adventurous, and to demonstrate I'm not a charlatan, add the following dependency to your POM:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
and then attempt this:
WebTarget target = ClientBuilder.newClient().target("http://stackoverflow.com/");
System.out.println(IOUtils.toString((InputStream) target.request().get().getEntity(), "UTF-8"));
You will be rewarded with a textual rendering (on standard output) of the StackOverflow home page – equivalent to performing a "view source" operation in your browser.
I don't know what your ultimate goal is, but if you're attempting to build anything useful from information on the StackExchange network, I suggest use of their APIs documented here.
Best of luck!
I got the same exception when using Apache CXF REST client in JavaFX project. The code is below:
MyClass rest = (MyClass) JAXRSClientFactory.create(endpoint, MyClass.class, Collections.singletonList(new JacksonJsonProvider()));
System.out.println("Service health: " + rest.health());
A test with plain Java project works fine with the same code and same dependencies. It is apparently a conflict between JavaFX and Apache CXF. I am trying to figure out why.
If you guys already solved this issue, that should be great to update this thread, which is the only result on Google search.
Updated solution:
After a while, I found that the default Maven project does not include enough the dependencies in the plugin "maven-dependency-plugin". I tried to add more packages in the list but still not work. So the final solution is in this thread: How to package an Apache CXF application into a monolithic JAR with the Maven "shade" plugin. Shade plugin is much better and works.

How can I retrieve snapshot dependencies from Nexus using SBT?

I have a maven2 repository from which I'm trying to fetch an snapshot artifact with an appended timestamp. I'm (unsurprisingly) able to retrieve it fine when building with maven2 but when building with simple-build-tool (sbt), much preferred by me, I can't pull it down.
I can see from this question about snapshots in Ivy that it is possible to configure Ivy to get snapshot artifacts but I don't know how to tell sbt to do it.
The relevant bits of my current configuration:
val snapshotsName = "Snapshots Repository"
val snapshotsUrl = new java.net.URL("http://host:port/path/to/root")
val snapshotsPattern = "[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
val snapshots = Resolver.url(snapshotsName, snapshotsUrl)(Patterns(snapshotsPattern))
Credentials(Path.userHome / ".ivy2" / ".credentials", log)
Update: After some more tinkering it looks like I can get it to point at the correct artifact url with the following pattern.
val snapshotsPattern = "[organisation]/[module]/[revision]-SNAPSHOT/[artifact]-[revision](-[timestamp]).[ext]"
With that I still need to specify the timestamp extra in the dependency
val dep = "group" % "artifact" % "0.0.1" extra("timestamp" -> "20101202.195418-3")
but it does pull the artifact. However it does NOT pull the artifact's dependencies. So it seems I've still got something wrong.
Alright, I got this sorted out but it wasn't actually an SBT problem it was 100% user error.
The Nexus I was using required authentication. I didn't have the authentication credentials set up correctly (see my authentication question) and because it wasn't properly authenticating it wasn't finding the metadata pom files and so SBT printed out the error message that it was failing I, incorrectly, assumed it was authenticating but not resolving. So I started messing with the patterns as evidenced in the actual question.
However, now that I have authentication setup correctly I changed back to just a regular repository declaration like so:
val snapshotsRepo = "Snapshots Repository" at "http://host:port/path/to/snapshots/root/"
and everything works. Artifacts are retrieved and dependencies resolved.