joelittlejohn / jsonschema2pojo

Generate Java types from JSON or JSON Schema and annotate those types for data-binding with Jackson, Gson, etc
http://www.jsonschema2pojo.org
Apache License 2.0
6.24k stars 1.66k forks source link

Kotlin Support? #593

Open jmfayard opened 8 years ago

jmfayard commented 8 years ago

Hello, Would it be in the scope of this project to add support for the Kotlin programming language .

Given the example available at http://www.jsonschema2pojo.org, it would generate the following data class

package com.example;

data class Example(
    val foo: String, 
    val bar: Int, 
    val baz: Boolean, 
    val additionalProperties: Map<String, Any> = emptyMap())

If that's the case, since jsonschema2pojo is a pretty useful tool, I would be interested in participating to add this feature

joelittlejohn commented 8 years ago

Hi @jmfayard, thanks for raising this. I've written some thoughts on #598 and this same applies to this one. Feel free to add comments there. Cheers.

evgenru commented 7 years ago

try it - https://plugins.jetbrains.com/plugin/8113-pojo-generator

simontb commented 7 years ago

Wanted to raise the same issue, but found this one. Thanks for explaining in #598.

@jmfayard what I do is that I create a Java class with jsonschema2pojo and let IntelliJ (or in my current case Android Studio) convert that class to Kotlin. Then all I do is to make it a data class, change the curly brackets to curved ones, add a comma after each variable, and if required make the objects non-null. This still saves me a lot of time.

joelittlejohn commented 7 years ago

I do have one question for Kotlin users: is there any viable way to generate Kotlin right now from outside Intellij? It seems like Jetbrains are keeping it there for now :(

simontb commented 7 years ago

I am not sure what you mean by 'generate'. Square has a tool to generate Kotlin files: kotlinpoet. Is this what you're looking for?

simontb commented 7 years ago

In #769 you asked for a way to generate Kotlin code outside of IntelliJ. Today I discovered that https://try.kotlinlang.org has a button 'Convert from Java', maybe this is what you're looking for.

joelittlejohn commented 7 years ago

@simontb Ooh, exciting. I wonder if that whole site is in GitHub.

I guess given that JetBrains runs the language, and Intellij, they may have given themselves their own hook into the IDE functionality. Good find though.

hIUG commented 7 years ago

It would be cool to include the @Parcelize annotation on this feature if ever implemented. I also would like to participate.

benju69 commented 6 years ago

+1

locofrank commented 6 years ago

+1

locofrank commented 6 years ago

want this

yura-f commented 6 years ago

+1

clevertrevor commented 6 years ago

+1

volkert-fastned commented 5 years ago

I do have one question for Kotlin users: is there any viable way to generate Kotlin right now from outside Intellij? It seems like Jetbrains are keeping it there for now :(

@joelittlejohn You might find this answer on StackOverflow helpful: https://stackoverflow.com/a/31498603

Basically, the answer refers to a unit test for the j2k module in the Kotlin repository on GitHub. That's the module responsible for the functionality that allows conversion of Java code to Kotlin code within IntelliJ IDEA. As this functionality is part of the community edition of IntelliJ IDEA, the source code of the j2k module is apparently available under the Apache 2 license, just like jsonschema2pojo. That means you should be able to integrate the j2k code into jsonschema2pojo without any legal problems. πŸ˜ƒ

However, it might be preferable if someone packages the j2k module as a separate library and pushes it to Maven Central, so you can easily keep it up-to-date with upstream. I'm frankly surprised no one has done this yet.

I really hope you'll be able to implement Kotlin support in jsonschema2pojo soon. There are many JSON to Kotlin data class converters out there, but none of them seem to support JSON Schemas. Your project is apparently the only one that supports the generation of POJOs based on JSON Schemas. Having to work with POJOs without null safety really sucks. And the lack of Lombok support in jsonschema2pojo rules that out as an alternative. 😞

Here's the direct link to the j2k code: https://github.com/JetBrains/kotlin/tree/master/j2k

Please let us know if we can help you with this in any way. Thanks again for the hard work on this project. I hope this writing doesn't come off as ungrateful. It's just that your project could be even more awesome if it supported the automatic generation of Kotlin data classes with automatic native null-safety for required JSON properties. Please make this happen! Thanks. ☺️

joelittlejohn commented 5 years ago

Thanks @volkert-fastned. I'd love to get Kotlin and Lombok support in.

It bugs me when the ecosystem of core tools around a language is tied tightly to a specific IDE. I'd love to see things like j2k spun out as re-usable libraries as you describe. Maybe you could do that?

volkert-fastned commented 5 years ago

I'll see what I can do.

volkert-fastned commented 5 years ago

@joelittlejohn Since we're having a Hackathon this week, it seemed like a good opportunity to dive into this today. πŸ™‚

So I started by building the j2k module of the (quite large) Kotlin code base. It took a long time just for j2k to build, since it apparently had a lot of dependencies on its sibling modules, requiring them to be built as well. However, I managed to build what I thought was a nice standalone JAR. I used mvn install:install-file to install the JAR to my local Maven repository in ~/.m2, after which I included the JAR as a Maven dependency in another project, in which I then tried to successfully call JavaToKotlinConverter.filesToKotlin(), as described in that StackOverflow answer I referred to earlier.

Unfortunately, the code in j2k appears to be very tightly coupled with Jetbrains/IntelliJ code. 😞 For one thing, it expects some kind of IDE context to work in, including an instance of the interface Project, which I assume is supposed to represent an actual opened project in IntelliJ IDEA. I tried both using the provided MockProject implementation and implementing the Project with a stub. I didn't get either to work. While running my unit tests in which I was trying out the code, I kept getting "Method not Found" exceptions w.r.t. Picocontainer. I tried adding Picocontainer as a dependency and then downgrading it to an older version, but all of that didn't work either.

Long story short, I spent the better part of the day trying to use the j2k code as a standalone library, but I was not successful. I tried diving a bit further into the code, in an attempt to peal off the layers and to see if I could perhaps find some more generic or independent class/code conversion logic underneath that I could perhaps access or reuse directly. For that, I opened the kotlin project in IntelliJ IDEA. Unfortunately, the project is so huge, that I had to wait for about half an hour to index all the files, even on a pretty fast system with lots of RAM. I studied it in detail yet, but so far, even at a lower level, the functionality really seems to tie in pretty intricately with Jetbrains IDE frameworks.

The test code that the StackOverflow answer referred to apparently makes use of a lot of framework mocking code in order to work programmatically outside of an IDE. Perhaps this test/mocking framework could somehow be used as application code and wrapped in a standalone library, but it doesn't appear trivial. This will take quite a bit of work.

I guess that was to be expected. After all, if the j2k code had been easy to use standalone, someone (perhaps even Jetbrains themselves) would probably have already published it as a library to Maven Central by now. Β―\_(ツ)_/Β―

Of course, it may be possible that I overlooked some very obvious solutions w.r.t. getting j2k to work as a standalone library. Anybody who has any more and/or better insights on this, please chime in!

I also googled a bit for some other possible projects that could convert Java to Kotlin conversation independently from an IDE. I found something called kj2k, but that project hasn't been worked on for 7 years.

At this point, I wonder whether it would actually be less effort to just write something that can convert JSON Schemas straight to Kotlin code, preferably Kotlin data classes. There are several third party projects that can convert JSON (but not JSON Schemas) to Kotlin data classes. Perhaps those could be extended to support JSON Schemas as input as well. Or alternatively, perhaps we should just implement a clean JSON Schema to Kotlin data class converter as part of jsonschema2pojo.

What do you think?

volkert-fastned commented 5 years ago

By the way, for anyone wanting to investigate this further, this is what I did to build the j2k JAR(s) independently (using JDK 8):

git clone https://github.com/JetBrains/kotlin.git
cd kotlin/j2k/

JAVA_HOME=/path/to/jdk8 JDK_18=/path/to/jdk8 ../gradlew clean build
JAVA_HOME=/path/to/jdk8 JDK_18=/path/to/jdk8 ../gradlew test
JAVA_HOME=/path/to/jdk8 JDK_18=/path/to/jdk8 ../gradlew jar

mvn install:install-file -Dfile=build/libs/j2k-1.3-SNAPSHOT.jar -DgroupId=org.jetbrains.kotlin -DartifactId=j2k -Dversion=1.3-SNAPSHOT -Dpackaging=jar

# Wasn't sure what groupId to use here, since the JAR contains code in multiple packages.
mvn install:install-file -Dfile=dependencies/repo/kotlin.build/intellij-core/183.5153.4/artifacts/intellij-core.jar -DgroupId=org.jetbrains -DartifactId=intellij-core -Dversion=183.5153.4 -Dpackaging=jar

Then I added these locally installed dependencies to the POM of a separate project to try consuming the library:

<dependency>
    <!-- I added this dependency later, when I started getting runtime errors, but it didn't help. -->
    <groupId>org.picocontainer</groupId>
    <artifactId>picocontainer</artifactId>
    <!-- I tried version 2.2 as well, that didn't work either. :-( -->
    <version>2.15</version>
</dependency>
<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>intellij-core</artifactId>
    <version>183.5153.4</version>
</dependency>
<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>j2k</artifactId>
    <version>1.3-SNAPSHOT</version>
</dependency>
joelittlejohn commented 5 years ago

@volkert-fastned Thank you for this amazing write up! I can imagine how thankless this task was, particularly when you find some new layer of interconnectedness with Intellij that ruins all your progress :) It's so disappointing when useful language tools are tightly bound into a IDE like this, but thanks for investigating so thoroughly.

So yes, I think the answer is kotlinpoet, and to introduce some kind of abstraction in jsonschema2pojo to allow the target language to be swapped based on configuration. I'm sure we'd get better Scala this way too :)

This brings me back to my original comment on #598 though. This idea may well be better implemented as an entirely new project.

volkert-fastned commented 5 years ago

@volkert-fastned Thank you for this amazing write up! I can imagine how thankless this task was, particularly when you find some new layer of interconnectedness with Intellij that ruins all your progress :)

Yeah, Hackathon projects are usually more fun than this. πŸ˜… But I'm glad I at least took a stab at it, even if for no other reason than to rule it out.

It's so disappointing when useful language tools are tightly bound into a IDE like this, but thanks for investigating so thoroughly.

I absolutely agree. Why not offer something this useful as a reusable library? πŸ˜• This code is part of the IntelliJ IDEA Community Edition, so it's not like it's a closely guarded proprietary feature. If anything, it would benefit the Kotlin ecosystem and community even more! Hmmm... Perhaps one of us should just open a feature request in their YouTrack issue tracker. "Please decouple and refactor j2k to a standalone library." πŸ€”

So yes, I think the answer is kotlinpoet, and to introduce some kind of abstraction in jsonschema2pojo to allow the target language to be swapped based on configuration. I'm sure we'd get better Scala this way too :)

This brings me back to my original comment on #598 though. This idea may well be better implemented as an entirely new project.

KotlinPoet looks interesting indeed. When you suggest a new project or a fork from jsonschema2pojo, do you also mean the Scala stuff, since you foresee a solution that would work well for both Scala and Kotlin? Or am I misunderstanding you?

volkert-fastned commented 5 years ago

Your comments in issue #598 seem to already answer my question. I was just wondering, since jsonschema2pojo already has partial Scala support.

Anyway, Scala is outside the scope of what I'm focusing on (Kotlin), so as a next step I'm going to see how easy it will be to write a rudimentary JSON Schema to Kotlin data class converter. I'll shamelessly steal whatever code from jsonschema2pojo I can reuse for this. This hackathon might prove to be fun yet. πŸ˜„

Thanks again!

volkert-fastned commented 5 years ago

@joelittlejohn Even though there doesn't appear to be a "quick fix" solution for implementing Kotlin support in jsonschema2pojo for the time being, implementing proper Lombok support and proper @Nullable annotations (see https://medium.com/quick-code/the-case-of-npe-in-interop-between-java-and-kotlin-8790b2b73e18) would result in POJOs that would be much less painful and more convenient to use from within Kotlin JVM projects. After all, Lombok pretty much provides the same advantages as Kotlin data classes do. Of course this would only be the case for Kotlin JVM projects. For Kotlin Native, Kotlin.js and Kotlin Multiplatform projects, Lombok support would be useless and only generated native Kotlin code would work.

Long story short, once #166 is implemented, the generated POJOs will be practical for use in most Kotlin (JVM) projects.

mnayef95 commented 4 years ago

+1