Skip to content
This repository has been archived by the owner on Mar 21, 2021. It is now read-only.

Enriching the JDL grammar #141

Closed
MathieuAA opened this issue Aug 28, 2017 · 26 comments
Closed

Enriching the JDL grammar #141

MathieuAA opened this issue Aug 28, 2017 · 26 comments

Comments

@MathieuAA
Copy link
Member

MathieuAA commented Aug 28, 2017

From the generator's original post here

Syntax in consideration:

commonConfig.jdl

BASE_PORT 8080 // common constants

application abstract BaseApp { // Implies that the app is abstract and will not be generated
  config {
    groupId "org.comp.proj"
    authenticationType "jwt"
    cache "hazelcast"
    serviceDiscoveryType "eureka"
    buildTool "maven"
    serverPort BASE_PORT
    packageName "org.comp.proj"
  }
}

entity abstract A {} // Implies entity is abstract and will not be generated unless referred to from an application
entity abstract B {}
entity abstract C {
    String name
}

service abstract AService { // Implies service is abstract and will only be generated when referred from an application
    Customer findByName(String name)
}

myMicroservice1JDLFile.jdl

import commonConfig.jdl             // import common configuration

application MyMicroservice1 {
  type 'microservice'
  config extend BaseApp {           // extend base app config
    serverPort (BASE_PORT + 100)
    databaseType "mongodb"
  }

  entity MyOnlyEntity extends C {     // one entity of the service extends one from commonConfig.jdl
    // this will have the field name generated as it extends entity C
    String code
  }

  services AService      // refers to external services from commonConfig.jdl
  service MyOnlyService {
    Customer findByName(String name)
  }

  paginate * with pager
  service * with serviceImpl
}

myGateway.jdl

import commonConfig.jdl             // import common configuration
import myMicroservice1JDLFile.jdl   // import microservice 1
import myMicroservice2JDLFile.jdl   // import microservice 2 and so on
import dockerConfig.jdl             // import docker compose setup

application MyGateway {
  type 'gateway'
  config extend BaseApp {           // extend base app config
    databaseType "Postgresql"
    clientFramework "react"
  }

  entities A, B                       // refers to external entities from commonConfig.jdl
  entity MyOnlyEntity extends C {     // one entity of the gateway extends one from commonConfig.jdl
    // this will have the field name generated as it extends entity C
    String code
  }

  relationship ManyToMany {
      A{b} to B{a}
  }

  services AService      // refers to external services from commonConfig.jdl
  service MyOnlyService {
    Customer findByName(String name)
  }

  paginate * with infinite-scroll
  service * with serviceImpl
}

This will generate

├── my-gateway
│   ├── pom.xml
│   └── src
│       └── main
│
├── my-microservice-1
│   └── pom.xml
|
├── my-microservice-2
│   └── pom.xml
├── docker-compose 
@colameo
Copy link
Member

colameo commented Aug 28, 2017

Please keep in mind, that changes in the JDL grammar affects the community which uses jhipster-ide. Since the ide features were introduced we have 300-500 installation per month and as you can imagine a change in the JDL would affect those people...

Beside of that, I also like the idea to improve the JDL grammar ;-) and thought to implement a kind of "Xjdl" (which stands for eXtended JDL) with feature similar to what you discussed in the issue #6275.

So I'm looking forward to this...

@deepu105
Copy link
Member

Colameo, the changes will be mostly backward compatible I believe

@MathieuAA
Copy link
Member Author

Yes. The only breaking change I've ever made was about regexes (the separator is now / instead of ').

@colameo
Copy link
Member

colameo commented Aug 28, 2017

@MathieuAA - ok that's good, that means we do not have pressure to integrate all changes in sync with yours.

@agoncal
Copy link

agoncal commented Aug 28, 2017

@deepu105 I liked the abstract and the type microservice, this leaves other possibilities.

Deepu, I didn't get the difference between services (plural) and service singular in your post : jhipster/generator-jhipster#6275 (comment). You wrote entity MyOnlyEntity (singular) and services MyOnlyService (plural). Is this a typo ?

 entity MyOnlyEntity extends C {     // one entity of the service extends one from commonConfig.jdl
    // this will have the field name generated as it extends entity C
    String code
  }

  services MyOnlyService {
    Customer findByName(String name)
  }

@MathieuAA
Copy link
Member Author

@agoncal it must be.
@jhipster/developers, @bd82, @hakandilek My main goal this week will be to get the app generation up and running. This means being able to generate apps from one or more JDL files, without generating entities right after (this comes after).

@deepu105 Do you think it will be easy to update the subgen to make it generate an application?

@deepu105
Copy link
Member

@MathieuAA yes the import-jdl sub gen can be easily updated to compose the app sub gen based on the app configuration/yo-rc generated. Unfortunately, I'll be on vacation from tomorrow until 8th of September so I won't be of much help. I can, of course, review things from my phone. But this should be straight forward just follow the same way entity generator is composed.

@agoncal might be a typo, I meant singular/plural in the same meaning as you guys did.
Also I would prefer to start with service creation and not repository as we already have a service sub gen to handle and also as per our policies it brings more value(repository can be easily hand created as its just adding method to an interface) for service we could create the service skeleton, a REST interface for that and so on. I guess you will achieve the same result that you expected with the repository keyword

@deepu105
Copy link
Member

@MathieuAA
Copy link
Member Author

@deepu105 thanks for adding the syntax! I'll work on it this week and submit a PR.

@deepu105
Copy link
Member

@MathieuAA take look at the PR from @bd82 before you start as it might be useful

@MathieuAA
Copy link
Member Author

@deepu105 Yeah I've had a look yesterday, and I agree with you

@agoncal
Copy link

agoncal commented Aug 29, 2017

@deepu105 I was thinking of your idea of "inheritance".

If you have a repository :

repository MyRepo {
 int countByAge(int age);
}

With this code, you have a valuable repository (valuable, because you can use it and it works), it's associated service and REST controller. Everything works.

Now, for a service:

service MyService {
 String myMethod(int param);
}

What do you do with it ? What do you generate ? And empty method ? What for ? You would have to add code on it. Coming back to your idea of inheritance, what about generating the following code:

public class MyService {
  public abstract String myMethod(int param);
}

public class ExtendedMyService extends MyService {
  @override
  public String myMethod(int param) {
    // add your code
  } 
}

This would allow to regenerate JHipster code easily (here, the MyService class) and creates an extension point for developers (using the ExtendedMyService).

WDYT ? Is that what you had in mind ?

@deepu105
Copy link
Member

@agoncal overall I would like to move to an Inheritance model for our generated code so that people can update the child classes without having to worry about being overwritten by upgrades and stuff.

Now for the repository vs Service. I belive if you generate a repo with say

repository MyRepo {
 int countByAge(int age);
}

You would create a Spring Data Interface called MyRepo with a method on it called countByAge and you could generate a Spring service class called MyRepoService with method countByAge which calls MyRepo.countByAge and a Rest Resource called MyRepoResource with method countByAge which calls MyRepoService.countByAge (I hope this is what you meant) IMHO this is not very valuable as it wont take much effort or time to create the same using an IDE.
Exact same classes and methods can be generated by below as well

service MyService {
 String myMethod(int param);
}

What I would rather prefer would be to be more flexible and provide a way to create service (as repository is too easy to hand code, just a spring data interface with methods) so you can do something like

service MyService {
 String myMethod(int param)
 Int countByAge(int age)
}
decorate MyService with repository, resource, serviceImpl

This will generate a resource class with end point for both methods (GET by default) the methods will call corresponding methods from service, an interface and impl for the service which will call repository methods. A spring repository. Here though its not too much value its faster to create different combinations and then customize it. And yes inheritance model would be nice on it as well

@agoncal
Copy link

agoncal commented Aug 29, 2017

@deepu105 I agree that you can create Spring Data interface + service + REST controller using an IDE... but being able to do it in JDL is important.

The way I work with JHipster is that I never touch the generated code, and only use inheritance. This allows me to upgrade my projects. In in my JDL I have a :

repository MyRepo {
 int countByAge(int age);
}

I know it will be in the generated code, and I know I won't have to touch it when upgrading JHipster. If you think of JHipster being an "IDE code generator", then, I can either use JHipster to generate a repository+service+controller or the IDE.

Services is where the business logic happens:

service MyService {
 double myComplexCalculation()
}

With this code, there is not much you can do. For my model of programming (inheritance) this would not help me.

You idea of decoration is great. You could even go:

entity MyEntity {
 String name
}
decorate MyEntity with repository, resource, serviceImpl

@bd82
Copy link
Contributor

bd82 commented Aug 30, 2017

@deepu105 , everyone.

How large of an enrichment of the grammar are we talking about here?

I'm trying to figure out how the questions of:

  • "How?" (technologies/architecture)
  • and "What?" (Syntax and Semantics of expanded JDL)
    Interact?

If most of the Grammar will effectively be redesigned, we may want to answer the
"How?" question first to avoid duplicate work.

If this enrichment mostly affects things outside the grammar and there will only be a moderate amount of syntax changes perhaps it does not matter and the tracks can be executed independently and in parallel.

@agoncal
Copy link

agoncal commented Nov 3, 2017

Another idea is also to be able to generate Enums that are not related to Entity (see #167)

@taurus227
Copy link

taurus227 commented Nov 6, 2017

This part of the original issue was not brought over, so I copied it here:

Uniqueness

Today we have several validations on our attributes (required, minlength, maxlength, pattern). We could have unique.

entity MyEntity {
  myCode String unique,
  myField String required,
  mySecondField String
}

This would generate a @Column(unique = true) as well as a Liquibase constraint :

  <addUniqueConstraint columnNames="code"
  tableName="mytable"
  constraintName="my_unique_code"/>

Issue #18 also proposed unique constraints, but it actually went one step further, proposing a way to specify multi-column unique constraints, like so:

unique { entityA{columnA, columnB} }

This could then generate the composite unique constraint in Liquibase.

If you agree that this would be useful, I'd be happy to contribute this feature. However, being a jhipster rookie, could somebody point me in the right direction, like what are the parts that would need modifications?

@MathieuAA
Copy link
Member Author

MathieuAA commented Nov 7, 2017

All, I agree to the unique thing as long as it doesn't look like unique { entityA{columnA, columnB} }. If we implement it, we'd have to have this syntax for every field validation, and it just isn't right. A field validation is only relevant to a field, its field, not the class or the file.
The syntax should be:

entity A {
  mySuperImportantField String required unique,
  myNotSoImportantField Integer max(42),
  myOtherImportantField unique
}

If it's implemented in the generator and the other JHipster devs agree to it (incidentally a PR for this would be nice in the generator), I'll add it to the JDL.

Now for this, a new issue should have been created (or posting in the first one) instead of adding yet another topic to this already impressive thread.

@deepu105
Copy link
Member

deepu105 commented Nov 7, 2017

I guess we were clear in another thread that we won't afd unique validation as there is no added value. So for now it is out of scope lets not do it. Lets finish the basic grammar we agreed above and later we can think of other enhancements

@agoncal
Copy link

agoncal commented Sep 21, 2018

@MathieuAA just tried JDL v2 : well done !

@deepu105
Copy link
Member

@agoncal did you try JDL v3? with the microservice stack generation jhipster/generator-jhipster#8335

@agoncal
Copy link

agoncal commented Sep 21, 2018

@deepu105 Current project is a monolith with Keycloak. Haven't had the chance to use microservices in v3... but will certainly give it a try ;o)

@antarus
Copy link

antarus commented Oct 31, 2018

Hello, @MathieuAA
I need the notion of extends and abstract for entities at work. I will be able to watch the generator part of this feature.
But I have some question:

  • how will be saved the notion 'extends' in the entity.json file?
  • how will be saved the notion 'abstract' in the entity.json file?
  • Take advantage of it to generate a BaseEntity (Add a BaseEntity to extends from all JHipster entity jhipster#45) ?
  • Should I add the notion of extends in questions for the generation of entity, or we keep this notion for the jdl?

@Tcharl
Copy link
Contributor

Tcharl commented Nov 2, 2018

Let me disturb that conversation a little ^^ ;-).

If the goal of this new syntax is to ease JH upgrade without modifying code, it may be wise to focus on other aspects. If we take generated elements from the ground up:

  • Entities are not extensible for now, and it looks really complicated to achieve using JDL. We can mitigate this adding more capabilities on them (audit, versions, String as Id, uniqueness, ...) and being full JPA compliant (but without inheritance ;-)
  • Repositories are extensible and extension can be automatically injected using @primary annotation
  • Service are extensible (we're doing it using ServiceImpl, which we find more appealing in the code).
  • DTO aren't extensible (like entities)
  • Mappers are extensible, but must be referenced as mapper extension in the service or other mappers
  • Resources are extensible, but we've to offer another endpoint (if we have the ability to generate an extension, may be we can avoid generating the @resource of the superclass)
  • Angular services are extensible, but without using 'providedIn('root')'
  • Angular crud are maybe extensible (didn't tested).

May be adding a notion of extensibility on entities could be nice?

@sidebyside {
Service,
Repository,
Resource,
ClientService
}
entity ExtendedEntity {}

Or even better being inspired by the EMF XCore like or VPDSL syntax

@generation {
Entity(skip), //skip|true defaults to true
Repository ([{jpa: decorate}, {search: true}], //skip|true|decorate defaults to true
DTO({mapstruct: decorate}), //skip|true|decorate defaults to true
Service (impl, decorate), //impl|class|decorate defaults to class
Resource(decorate), //true|decorate defaults to true
ClientService(decorate) //true|decorate defaults to true
}
entity ExtendedEntity {}

With one or the other, we could avoid the 'repository' and 'service' keyword which are in this form kind of overkill for what they achieve IMHO.

Also, I really like the notion of generic definition extension and abstraction, which would be very useful in many cases, circumventing the actual impossibility to have the same entity in two microservices which is frequent when doing client-server.

I'm finally inline with the point of cbornet: we should be able to host a full microservice definition by jdl file, which is impossible today, due to the generic configurations like search, skipClient, and so on.
May be a little trick concatenating every imported jh values for a property could do the trick.

@deepu105
Copy link
Member

deepu105 commented Nov 3, 2018

I have been working on some JDL syntax and feature enhancements. Ill share them soon, for the record I don't want to change any existing syntax, I think they are quite simple and nice, which is more important. Let me write up about what I have in mind later.

@deepu105 deepu105 mentioned this issue Nov 3, 2018
@deepu105
Copy link
Member

deepu105 commented Nov 3, 2018

closing in favor of #277

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants