GithubHelp home page GithubHelp logo

adevintaspain / protein Goto Github PK

View Code? Open in Web Editor NEW
274.0 11.0 8.0 6.68 MB

💊 Protein is an IntelliJ Plugin to generate Kotlin code for Retrofit 2 and RxJava 2 based on a Swagger definition

Home Page: https://plugins.jetbrains.com/plugin/10206-protein--android-component-builder

License: Apache License 2.0

HTML 5.51% Java 42.89% Kotlin 50.69% Shell 0.92%
codegenerator android kotlin swagger intellij-plugin kotlinpoet rxjava2 codegen plugin retrofit2

protein's Introduction

* IntelliJ Kotlin code generator for Retrofit2 and RxJava2 based on Swagger *

Version Downloads

Protein is a plugin for intelliJ that automates the build of Retrofit "Interfaces" and "models" for Android in Kotlin. It generates the code for Retrofit based on a Swagger endpoint.


Background | Features | Download | Who Made This | Apps using Protein | Contribute | Bugs and Feedback | License


Background

Protein: A large molecule composed of one or more chains of amino acids in a specific order; the order is determined by the base sequence of nucleotides in the gene coding for the protein. Proteins are required for the structure, function, and regulation of the body’s cells, tissues, and organs, and each protein has unique functions. Examples are hormones, enzymes, and antibodies.

This scientific definition defines quite good the objective of this Plugin in an abstract way. For many time at Adevinta Spain we struggled with the idea of making a good and maintainable architecture for Android. It's been some time until we got one that fits with our needs but we still have a lot of errors and issues that human beings do every time we make manual work. That's were we came to the idea of automatization and make new components with all we need.

Protein is our approach to work better, be more productive and reliable.

NOTE: Protein is based on the library Retroswagger that is the core for the kotlin builder that parses swagger json and generates the kotlin code.

Features

  • Easy interface
  • Interface and Models auto-generated
  • Swagger integration: create code based on swagger documentation
  • IntelliJ and Android Studio compatible

Requirements

To use it you need a Swagger schema endpoint (example: http://petstore.swagger.io/v2/swagger.json).

Example

Swagger json code
{
  "swagger":"2.0",
  "info":{
    "version":"1"
  },
  "host":"localhost:8000",
  "basePath":"/",
  "tags":[
    {
      "name":"favorites-controller",
      "description":"Favorites Controller"
    }
  ],
  "paths":{
    "/favorites":{
      "get":{
        "tags":[
          "favorites-controller"
        ],
        "summary":"Get all favorites for this user",
        "operationId":"getFavorites",
        "consumes":[
          "application/json"
        ],
        "produces":[
          "application/json;charset=UTF-8"
        ],
        "parameters":[
          {
            "name":"Authorization",
            "in":"header",
            "description":"Authorization",
            "required":true,
            "type":"string"
          }
        ],
        "responses":{
          "200":{
            "description":"OK",
            "schema":{
              "$ref":"#/definitions/GetFavoritesResponse"
            }
          },
          "401":{
            "description":"Unauthorized"
          },
          "403":{
            "description":"Forbidden"
          },
          "404":{
            "description":"Not Found"
          }
        }
      }
    },
    "/favorites/{adId}":{
      "put":{
        "tags":[
          "favorites-controller"
        ],
        "summary":"Save favorite",
        "operationId":"saveFavorite",
        "consumes":[
          "application/json"
        ],
        "produces":[
          "application/json;charset=UTF-8"
        ],
        "parameters":[
          {
            "name":"adId",
            "in":"path",
            "description":"adId",
            "required":true,
            "type":"string"
          },
          {
            "name":"Authorization",
            "in":"header",
            "description":"Authorization",
            "required":true,
            "type":"string"
          }
        ],
        "responses":{
          "200":{
            "description":"OK"
          },
          "201":{
            "description":"Created"
          },
          "401":{
            "description":"Unauthorized"
          },
          "403":{
            "description":"Forbidden"
          },
          "404":{
            "description":"Not Found"
          }
        }
      },
      "delete":{
        "tags":[
          "favorites-controller"
        ],
        "summary":"Delete favorite",
        "operationId":"deleteFavorite",
        "consumes":[
          "application/json"
        ],
        "produces":[
          "application/json;charset=UTF-8"
        ],
        "parameters":[
          {
            "name":"adId",
            "in":"path",
            "description":"adId",
            "required":true,
            "type":"string"
          },
          {
            "name":"Authorization",
            "in":"header",
            "description":"Authorization",
            "required":true,
            "type":"string"
          }
        ],
        "responses":{
          "200":{
            "description":"OK"
          },
          "204":{
            "description":"No Content"
          },
          "401":{
            "description":"Unauthorized"
          },
          "403":{
            "description":"Forbidden"
          }
        }
      }
    }
  },
  "definitions":{
    "FavoriteAd":{
      "type":"object",
      "properties":{
        "adId":{
          "type":"string"
        },
        "userId":{
          "type":"string"
        }
      }
    },
    "GetFavoritesResponse":{
      "type":"object",
      "properties":{
        "favorites":{
          "type":"array",
          "items":{
            "$ref":"#/definitions/FavoriteAd"
          }
        }
      }
    },
    "Single«ResponseEntity«GetFavoritesResponse»»":{
      "type":"object"
    }
  }
}
Retrofit2 + RxJava2 Interface generated in Kotlin

It will generate the interface and the models related to that interface.

package com.mycompany.mylibrary

import io.reactivex.Completable
import io.reactivex.Single
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.PUT
import retrofit2.http.Path

interface componentNameApiInterface {
    @GET("/favorites")
    fun getFavorites(): Single<GetFavoritesResponse>

    @PUT("/favorites/{adId}")
    fun saveFavorite(@Path("adId") adId: String): Completable

    @DELETE("/favorites/{adId}")
    fun deleteFavorite(@Path("adId") adId: String): Completable
}

Download

RELEASE

You can download it through the intelliJ/AndroidStudio plugin interface or you can check: https://plugins.jetbrains.com/plugin/10206-protein--android-component-builder

Build it yourself!

  1. If you want to build it locally you need download the latest version of IntelliJ Community https://www.jetbrains.com/idea/download/#section=mac
  2. Clone this repository ([email protected]:AdevintaSpain/protein.git)
  3. Execute "RunIdea" gradle task

Who made this

Ferran Pons
Ferran Pons

Apps using Protein

The following is a list of some of the public apps using Protein and are published on the Google Play Store.

Want to add your app? Found an app that no longer works or no longer uses Protein? Please submit a pull request on GitHub to update this page!

vibbo Fotocasa

Contribute

  1. Create an issue to discuss about your idea
  2. [Fork it] (https://github.com/AdevintaSpain/protein/fork)
  3. Create your feature branch (git checkout -b my-new-feature)
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request
  7. Profit! ✅

Bugs and Feedback

For bugs, questions and discussions please use the Github Issues.

License

Copyright 2018 Adevinta Spain S.L.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

protein's People

Contributors

carlosefonseca avatar diklimchuk avatar ferranpons avatar nucliweb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

protein's Issues

Crash using AS 3.5.1

When trying to launch Protein the following exception occurs:

java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of com/intellij/ide/plugins/cl/PluginClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of com/intellij/util/lang/UrlClassLoader) for the method's defining class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
	at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:418)
	at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)
	at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383)
	at com.bugsnag.Bugsnag.<clinit>(Bugsnag.java:26)
	at protein.tracking.BugsnagErrorTracking.<init>(BugsnagErrorTracking.kt:7)
	at protein.steps.PackageInfoStep.<init>(PackageInfoStep.java:35)
	at protein.AddComponentWizardModel.<init>(AddComponentWizardModel.kt:11)
	at protein.AddComponentWizard.<init>(AddComponentWizard.kt:9)
	at protein.AddComponentWizard$Companion.run(AddComponentWizard.kt:20)
	at protein.actions.AddNewComponentAction.actionPerformed(AddNewComponentAction.kt:10)
	at com.intellij.openapi.actionSystem.ex.ActionUtil$1.run(ActionUtil.java:261)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAware(ActionUtil.java:278)
	at com.intellij.openapi.actionSystem.impl.ActionMenuItem$ActionTransmitter.lambda$actionPerformed$0(ActionMenuItem.java:292)
	at com.intellij.openapi.wm.impl.FocusManagerImpl.runOnOwnContext(FocusManagerImpl.java:283)
	at com.intellij.openapi.wm.impl.IdeFocusManagerImpl.runOnOwnContext(IdeFocusManagerImpl.java:107)
	at com.intellij.openapi.actionSystem.impl.ActionMenuItem$ActionTransmitter.actionPerformed(ActionMenuItem.java:282)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
	at com.intellij.openapi.actionSystem.impl.ActionMenuItem.lambda$fireActionPerformed$0(ActionMenuItem.java:111)
	at com.intellij.openapi.application.TransactionGuardImpl.runSyncTransaction(TransactionGuardImpl.java:88)
	at com.intellij.openapi.application.TransactionGuardImpl.lambda$submitTransaction$1(TransactionGuardImpl.java:111)
	at com.intellij.openapi.application.TransactionGuardImpl.submitTransaction(TransactionGuardImpl.java:120)
	at com.intellij.openapi.application.TransactionGuard.submitTransaction(TransactionGuard.java:121)
	at com.intellij.openapi.actionSystem.impl.ActionMenuItem.fireActionPerformed(ActionMenuItem.java:111)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
	at javax.swing.JToggleButton$ToggleButtonModel.setPressed(JToggleButton.java:308)
	at javax.swing.AbstractButton.doClick(AbstractButton.java:376)
	at com.apple.laf.ScreenMenuItemCheckbox.itemStateChanged(ScreenMenuItemCheckbox.java:193)
	at java.awt.CheckboxMenuItem.processItemEvent(CheckboxMenuItem.java:389)
	at java.awt.CheckboxMenuItem.processEvent(CheckboxMenuItem.java:357)
	at java.awt.MenuComponent.dispatchEventImpl(MenuComponent.java:357)
	at java.awt.MenuComponent.dispatchEvent(MenuComponent.java:345)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:769)
	at java.awt.EventQueue.access$500(EventQueue.java:98)
	at java.awt.EventQueue$3.run(EventQueue.java:715)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
	at java.awt.EventQueue$4.run(EventQueue.java:739)
	at java.awt.EventQueue$4.run(EventQueue.java:737)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:736)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:706)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:375)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Event log says this exception is in Protein - Kotlin code generator.. on Swagger plugin

I'm using Android Studio 3.5.1 and the latest plugin version from AS marketplace

Type of Body parameters seems wrong.

Just tried Protein and it's looking pretty great, but I'm seeing something wrong:
the @Body argument: Type seems to be using the parameter name for the Type, instead of the schema defined on the swagger. All @Body arguments on the generated ApiInterface are unresolved and reference incorrect class names. The correct classes were created but aren't used.

To Reproduce
Generate code for a swagger that contains something like this in a request description:

  "parameters": [
          {
            "name": "requestPatch",
            "in": "body",
            "description": "Patch object containing the new state value",
            "required": true,
            "schema": {
              "$ref": "#/definitions/RequestUpdateStateDTO"
            }
          }
        ],

I believe this should generate something like

fun foo(@Body requestPatch: RequestUpdateStateDTO)

but it actually generates something like

fun foo(@Body requestPatch: RequestPatch)

Info Required

  • Plugin version 1.0

Nullability

Hi! Does it support the nullability fields? For example, if the backend will send the null as I understand, the app will be closed because of non-null fields in data classes.

Protein fails to generate proper code when objects have dots in their name

Describe the bug
Protein is a really cool tool, I like it! However, it has failed to generate right names for data classes.
Generated classes are like "data class Class.V1.API.Model", and their names are put in Kotlin captions ``.

To Reproduce
Just add dots in the object names in JSON file.
Example:

  "Company.MyAwesomeApi.Contracts.V1.Specific.SecondSpecific": {
            "type": "object",
            "properties": {
                "date": {
                    "format": "date-time",
                    "type": "string"
                },
                "extendedPropertyTypeId": {
                    "format": "uuid",
                    "type": "string"
                },
                "value": {
                    "type": "string"
                }
            }
        },

Expected behavior
The easiest way would be to trim dots and generate clients with CapitalCase naming convenetion (or camelCase):
CompanyMyAwesomeApiContractsV1SpecificSecondSpecific
The JSON file cannot be changed since it is generated via .NET code and they use dots for namespaces.

Info Required

  • Which version of the plugin do you actually use?
    The latest one - 1.1.2

  • Any other thing that could help me to reproduce the error?

Screenshots

Additional context

Openapi 3.0.0 support

Hi! Does this library support openapi 3 and if not, are there any plans on supporting it in the future? If i try to run the plugin with 'openapi: "3.0.0"' as the first line, an empty interface is generated and it's unclear whether it's not supported or some error happened.

Fails on language keywords

If you have a language keyword as one of your model names (e.g. break) it will fail, because its reserved.

Flux Error

Describe the bug
generates wrong codes when service returns flux and mono objects like

"responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/Flux«CommunityMemberResource»" } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not Found" } }
To Reproduce
Steps to reproduce the behavior:

We should have an option to decide about retrofit absolute/relative request path

Is your feature request related to a problem? Please describe.
I'm frustrated when I have to remove the first slash / for all Retrofit's annotations, like changing:
@post("/person/data")
to:
@post("person/data")

Describe the solution you'd like
This involves the case when the baseUrl for retrofit is nested, like:
"https://myApi/myEndpoint/v1/"

Describe alternatives you've considered
The alternative is to manually go though the file and remove slashes.

Additional context
We should have a checkbox in a plugin to check if we want absolute paths beginning with "/" (this would mean that "/myEndpoint/v1" would be trimmed in the basePath. Or if whether we want relative paths (without "/" at the beginning)

Query parameters are not added

Is your feature request related to a problem? Please describe.
If the endpoint has query parameters, the generated method doesn't add it.

Describe the solution you'd like
Add @query parameters to methods.

Describe alternatives you've considered
Nothing.

Additional context
Awesome plugin! Really helpful.

Not working well with android studio 3.4

In android studio 3.4 is not generating well the code

import io.swagger.annotations.ApiModel
import io.swagger.annotations.ApiModelProperty

@apimodel
final class ErrorMsg {
@ApiModelProperty
@SerializedName("message")
private var message: String
}

@get("/")
fun WelcomeMsg(): Observable

@get("/commit")
fun Commit(): Observable

LongArray body isn't generated as expected

I just noticed that if the body parameter is an Array of Long, like this:

    "parameters": [
      {
        "name": "messageIdentifiers",
        "in": "body",
        "description": "A list of chat message unique identifiers",
        "required": true,
        "schema": {
          "type": "array",
          "items": {
            "format": "int64",
            "type": "integer"
          }
        }
      }
    ],

the generated method is:

fun Blah(@Body messageIdentifiers: MessageIdentifiers)

instead of

fun Blah(@Body messageIdentifiers: LongArray)

Info Required

  • Which version of the plugin do you actually use?
    Version: 1.1.1

Plugin assumes you've only got one project open and that the project you're working with is the first one

Code blindly assumes you want to work against first open project.

To Reproduce

  1. Open more than one project in IDE
  2. Select a project window that isn't the first one
  3. Select New > Protein - Add new rest api interface
  4. You now get to select modules from the first project. Not whichever you actually tried to add stuff to

Expected behavior
You should be able to select from the modules in the active project

Info Required

  • Which version of the plugin do you actually use?
    1.0.0

I assume that this is a result of the lines in StorageUtils.java where getting the first of the open projects from the project manager is hard coded.

https://github.com/SchibstedSpain/Protein/blob/629e7206f2697df2e730f41598b6042553a9b763/src/main/java/protein/common/StorageUtils.java#L24

https://github.com/SchibstedSpain/Protein/blob/629e7206f2697df2e730f41598b6042553a9b763/src/main/java/protein/common/StorageUtils.java#L31

interface is Empty

Hi.
Do you know why the objects created successfully, but the interface is empty?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.