jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.53k stars 4.02k forks source link

[Enhancement] Hook mechanism improvements #2694

Closed amitjindal closed 8 years ago

amitjindal commented 8 years ago

Overview

This suggestion below stems from the discussion that happened on #2668 as @jdubois suggested running cycles for add/edit/delete entities and options about sub generators, this conversation got me thinking.

Below is merely a concept at this point and might not be feasible or a direction you want to take.

Background

May I humbly add a few observations based on a large project we are doing and the changes we have needed internally. We needed to make customisations so that the generated HTML was using a different style, some fields were needed to be customised, file uploads were stored on Amazon S3, entities were in a separate namespace and on different url (http://localhost:8080/api/v1/entities/customer), all URLs were lowercase and several other things here and there.

Thoughts

When @pascalgrimaud suggest to look at modules it was the first time I was reading them. I must confess I am very poor at yo generators so I may have completely misunderstood these. As I was reading it occurred to me that we can consider the jhipster generator and its hooks with sub generators as parent child or in object oriented world a base class/generator and a derived class/generator. Just like I could override a method, why can't I do that in JHipster generator. So what if they actually were like that and child generators had a way to customise how parent worked.

For reference: Hibernate has lifecycle events

(See: https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/listeners.html) JHipster in future may have the same along with its lifecycle that can allow the sub generators to change how core generator generates the code. Each of sub-generators could directly modify the JSON objects exposed by main generator so now generator behaviour get customised. I believe this may be the direction you have already taken with hooks.

So a 'app' generator lifecycle will be:

BeforeAskQuestions: Maybe used to preconfigure some settings or display a note. AfterAskQuestions: Used to add additional sub generator questions or maybe modify the answers. PreGenerate: Change paths like where entities or DTOs should be stored or customise the API path. PostGenerate: To add additional files/classes.

And an 'entity' generator lifecycle will be:

BeforeAskQuestions: Usually used to preconfigure some settings (maybe) AfterAskQuestions: Used to add additional sub generator questions or maybe modify the answers. PreGenerate: Change datatypes or add custom fields to Entities. For example this may be used to customise the 'ID' generator. So if I want Postgresql to have UUID's as primary key, a sub generator would do that. Similarly if I want to add a custom fields (like createdOn, createdBy, modifiedOn, modifiedBy) in all entities I can do that trivially here. PostGenerate: To add additional files/classes.

Preprocessed Datatypes for subgenerators to override

The generator may also preprocess the datatypes for each field so that logic may be reduced and overridden in sub generators if needed. So instead of conditionals based on say Mongo vs Cassandra, these could be pre-populated in an structure and then types can simply be used. For example in JS we could interpret something like (pseudo-code):

var fieldDataType = 'Long';  // MySQL or Postgresql
if (database == 'Cassandra') fieldDataType = 'UUID';

so then in code we can simply use:

foreach (field in fields)
   fieldDataType fieldName;

Even better if there was a sub generator, it could have changed the behaviour.

// Postgres Customised Generator.
foreach (field in fields)
    if (field.name == 'id') field.fieldDateType = 'UUID';

Using partial templates that sub generators can change

If you are familiar with .NET and shared templates, they have a beautiful design that defines how I can give a custom edit and view template to display for a datatype say datetime. So someone writing code can use all defaults but change how their datetime is rendered. A possible future version of JHipster could do that. I saw a recent refactoring to break the entities code in included files so applying that each datatype can be considered a partial template. The main generator is simply collecting the partial templates that compose an entity. Similar structuring can be applied to the HTML. So consider that I want to use a custom way to render date time. With above lifecycle (hooks), the base code generator will load the default templates and on PreGenerate hook I would simply provide a custom HTML to be used for DateTime editor.

So for each field I may have something like:

jhipster.templates.datetime.edit = '<appPath>/src/main/webapp/partials/zoneddatetime_edit.html'

and Child generator in PreGenerate could change that to:

jhipster.templates.datetime.edit = '<childpath>/src/main/webapp/partials/kendo_datetime_edit.html'

This opens the possibility that people can create their own templates that they can override in their own sub generator with core generator evolving on its own way.

deepu105 commented 8 years ago

The idea of having hooks is exactly to serve use cases like these. Though currently we only have a post entity creation hook, we could add pre entity, pre and post app creation hooks as well, we will be doing these as we get some good use cases.

Too much of hooks like you suggest will become too much of maintanance so may not be feasible and also the yeoman run cycle will not allow such hooks easily, that is why i decided to stop with pre/post hooks alone.

Inheritance and overloading is very tricky in javascript and within the yeoman framework we have to stick to yeoman principles as well.

We cannot cater for every single use case so the idea is to cater to most common and generic use cases. But still most of what you asked can be done with modules or by composing with jhipster, for some use case you might have to work around a little, explore some of the modules to get an idea.

Custom templates is a good to have but very complex to achieve feature, take a look at my react module, im trying to do a different front end than what jhipster provides so thats one way to achieve what you are asking but that means there will be some code duplication if you want to replace only partials

Any way lets see what others have to say

amitjindal commented 8 years ago

So the whole reason of mentioning these above is for a person who is using JHipster to do multiple projects. If they want to use a particular style or theme or use say a custom date time (just picking this as an example), they will need to make changes in all the projects again and again and in each entity by hand. I just thought of suggesting if the above is possible (with probably a big 'if'), it may be worth considering.

No worries. :-)

jdubois commented 8 years ago

Yes that would be great to have, but as @deepu105 says it's going to be a lot of work, and cause a lot of trouble. I'm not sure we can handle this amount of work.

deepu105 commented 8 years ago

if someone can comeup with a clever idea to hook templates easily then this could be worth exploring, and will make JHipster a one stop tool for any java webapp dev :)

amitjindal commented 8 years ago

I am currently a beginner with generators, but as I am exploring more if I see something I will definitely suggest and code.

deepu105 commented 8 years ago

I have added a post app run hook.

I'm not adding a pre entity/app run hook unless I have a good use case to test against.