GithubHelp home page GithubHelp logo

sporniket / javabeans Goto Github PK

View Code? Open in Web Editor NEW
0.0 2.0 1.0 651 KB

A project to convert Java POJO structures into Javabeans replicating the class hierarchy a.k.a. "Yet Another Javabeans Generator".

License: GNU Lesser General Public License v3.0

Java 99.97% Groovy 0.03%
java-bean java code-generator javabeans doclet javabeans-generator jpa-hibernate

javabeans's Introduction

Sporniket-Javabeans

[WARNING] Please read carefully this note before using this project. It contains important facts.

Content

  1. What is Sporniket-Javabeans, and when to use it ?
  2. What should you know before using Sporniket-Javabeans ?
  3. How to use Sporniket-Javabeans ?
  4. Known issues
  5. Miscellanous

1. What is Sporniket-Javabeans, and when to use it ?

Sporniket-Javabeans is a project to generate Javabeans from a tree of Java POJO structures. The generated tree of Javabeans replicates the POJO tree, supports generics. Additionnally, a fluent builder class is generated for each non abstract generated Javabeans.

Sporniket-Javabeans also provides a plugin to perform reverse engineering of an existing class hierarchy of Javabeans for the sake of helping as much as possible to migrate an existing project.

As of v20.04.01

Sporniket-Javabeans also provides seeg (Sporniket Entities Extractor and Generator), an application and maven plugin to perform generate a set of entities classes from a database (for now, only PostgreSql is supported), including enums, id classes and a few selectors.

Before Septembre 2017, it WAS a project to generate Javabeans from a XML model. Interested people may checkout the v15.04.00 or v15.04.01 and fork from there.

TODO list, a.k.a. "The roadmap"

In no particular order :

  • can generate boundable and constrainable properties (will use annotation)
  • allows true encapsulation of collections and maps (idem)
  • the fluent builder api 'done()' method name may be specified.

See also the known issues.

What's new in v23.07.00

  • #70 : [doclet][bug] the name of the class being defined is the fully qualified name when another class with the same simple name is already referenced

What's new in v20.07.01

  • #63 : [bug][seeg] dbml generation interrupted without trace

What's new in v20.07.00

  • #61 : [seeg] generate a dbml model

What's new in v20.05.02

  • #60 : : [bug][seeg] Finder classes must be parametrized using non native types

What's new in v20.05.01

  • #56 : [bug][seed] the id class require a no-args constructor

What's new in v20.05.00

  • #55 : [bug][seeg] Using PostGreSQL enums require custom types
  • #57 : [bug][seeg] Hibernate require correctly named fields for idclasses

What's new in v20.04.04

  • #53 : [bug][seeg]Hibernate cannot find properties of query method if internal name does not match

What's new in v20.04.03

  • #48 : [seeg] Have a mapper from Entity to IdClass - David SPORN (HEAD -> master, origin/master, origin/HEAD)
  • #49 : [bug][seeg] identity auto-incremented and sequence columns not recognized properly - David SPORN
  • #50 : [bug][seeg] Generate only enums from the target schema - David SPORN
  • #51 : [bug][seeg] Repository class with idclass is not generated - David SPORN
  • #52 : [bug][seeg] the id class must implements serializable. - David SPORN

What's new in v20.04.02

  • #45 : [bug][seeg] 'bigserial' type not supported
  • #46 : [bug][seeg] type 'serial' should be mapped to integer
  • #47 : [seeg] Use primary key columns for entity hashcode and equality

What's new in v20.04.01

  • 42 : Plugin to generate JPA entities and repositories from database
  • 44 : [seeg] implements compounded primary keys with @IdClass

What's new in v20.04.00

  • #26 : Generate a generic builder for a generated abstract bean
  • #39 : [Bug] Escape string values for annotations parameters
  • #41 : [bug] Some annotation need to be generated on the accessors too

What's new in v19.09.00

  • #22 : Copy javadoc comments - class and fields

What's new in v19.04.00

  • #34 : Support arrays fields

What's new in v19.03.00

  • #36 : Does not recognize field name prefix in pojo to expands
  • Use junit5 tests, add better coverage.

What's new in v19.02.00

  • Fixes an obvious problem of classname translation when looking for any replacement possible, e.g. when there are the following names to replace : PrefixClassOfThings, PrefixClassOfThingsSpecial, it tries to replace the longest first.

Fixes to the demo project :

  • #34 : Wrong format for additionnal parameters in demo pom
  • address critical vulnerability warning in demo project about jackson version

What's new in v18.10.01

  • #33 : Generate a builder that can handle a subclass. In other words, the builder has a default constructor to act as usual, and a constructor accepting an Javabean instance that should have been created.
//SampleGenerics<T,R extends Number> has been generated
static class Parametrized extends SampleGenerics<CharSequence, Double>
{
  public void doSomething()
  {
    System.out.println("hi !");
  }
}

//Sample use of the builder class
public static void main(String[] args)
{
  SampleGenerics<String, Long> sampleGenerics = new SampleGenerics_Builder<String, Long>()//
      // ...etc...
      .done();

  //Create a subclass instance
  Parametrized sampleGenericsSubclass = (Parametrized) new SampleGenerics_Builder<>(new Parametrized())
      // ...etc...
      .done();
  sampleGenericsSubclass.doSomething();
}

What's new in v18.10.00

  • #28, #30 : Support for class and field annotations, can handle typical use of Jackson annotations (@JsonProperty, @JsonTypeInfo and @JsonSubTypes)

What's new in v17.12.00

Technical matters :

  • #20 : Refactor code generation to separate data preparation from data injection into a template

Issues fixed :

  • #21 : The generated javabean imports class required by inherited fields
  • #23 : Generated classes import native types
  • #24 : Boolean/boolean read accessor should be prefixed by 'is' instead of 'get'

What's new in v17.09.01

Technical matters :

  • extending the code coverage using Mockito

Issues fixed :

  • #19 : Accessors are not following CamelCase

What's in v17.09.00

  • generate Javabeans with basic getter/setter (not bounded, not constrained).
  • fluent builder api, e.g. bean = new MyBeautifulBean_Builder.withId(...).withDescription(...).done() ;
  • reverse engineering of existing simple Javabeans hierarchy, to convert existing projects.

Licence

Sporniket-Javabeans is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Sporniket-Javabeans is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with Sporniket-Javabeans. If not, see http://www.gnu.org/licenses/ .

2. What should you know before using Sporniket-Javabeans ?

Sporniket-Javabeans relies only on standard jdk 8 and consists of :

  • Sporniket-Javabeans-doclet : contains ExpanderDoclet to generate Javabeans, and DistillerDoclet to reverse-engineer POJOs.
  • seeg-maven-plugin : 'Sporniket Entities Extractor and Generator' to generate your JPA entities and spring JpaRepositories base repositories

Do not use Sporniket-Javabeans if this project is not suitable for your project

3. How to use Sporniket-Javabeans ?

Using 'sporniket-javabeans-doclet'

See the demo project sporniket-javabeans-doclet-sample. It demonstrate :

  • Javabeans and POJOs generation, integrated in the build process of maven.
  • Typical supported java code support for conversion (e.g. generics, annotations).
  • Manual call in a sample program.

Using 'seeg-maven-plugin'

This tool require an accessible database with actual tables.

PostgreSQL is the only dbms supported for now

In your maven project, prepare a properties file describing the connection to the reference database, by default it will be ${project.basedir}/seeg-connection.properties, and containing the following keys :

  • url : jdbc url, e.g. 'jdbc:postgresql://localhost:54320/postgres'.
  • driverClass : jdbc url, e.g. 'org.postgresql.Driver'.
  • username : name of the database user, should have access to the schema.
  • password : password for the database user.

In your pom build section, declare and configure seeg-maven-plugin with the target package to generate (in the source folder) and an optionnal schema ; use the connectionConfig parameter to set the path to the properties file if it is not ${project.basedir}/seeg-connection.properties.

<plugin>
	<groupId>com.sporniket.javabeans</groupId>
	<artifactId>seeg-maven-plugin</artifactId>
	<version>${version.seeg-maven-plugin}</version>
	<configuration>
		<targetPackage>com.sporniket.lca.entities</targetPackage>
		<schemaName>lca</schemaName>
	</configuration>
</plugin>

Then, when ever you need to regenerate your entities, invoke seeg :

mvn seeg:seeg

4. Known issues

See the project issues page.

5. Miscellanous

Report issues

Use the project issues page.

javabeans's People

Contributors

dependabot[bot] avatar sporn-for-degetel avatar sporniket avatar

Watchers

 avatar  avatar

javabeans's Issues

Generate a generic builder for a generated abstract bean

When the generated javabean is abstract, like :

public abstract class SampleAbstractBean {
    private String mySampleProperty ;
    public String getSampleProperty() { return mySampleProperty ; }
    public void setSampleProperty(String sampleProperty) { mySampleProperty = sampleProperty ; }
}

Instead of prevent generating a Builder, generate a generic builder, like :

public class SampleAbstractBean_Builder<T extends SampleAbstractBean> {
    private T myInstance = new T() ;
    public SampleAbstractBean_Builder<T> withSampleProperty() { 
        T.setSampleProperty(sampleProperty) ; 
        this return; 
    }
    public T done() {
        T result = myInstance ;
        myInstance = new T() ;
        return myInstance ;
    }
}

[doclet][bug] Cannot use nested parametrized types

Steps to reproduce

  1. Write a FooRaw with the following field : Map<String, List<String>> headers;
  2. The generated code (field, accessors, fluent builders) defines headers as Map<String,List> instead of Map<String, List<String>> headers

Refactor code generation to separate data preparation from data injection into a template

For now the code generation mixes code generation using "printf" with computing the values given to those printfs.

In order to use a templating system like velocity, the data computation should result into a data structure containing any values to give to those printfs or the templating system

These "code specifications" will be gathered in a "codespecs" package, and named :

  • ImportSpecs : class name, directly required by javabean (not directly = required by inherited field)
  • AnnotationSpecs
  • JavadocSpecs (extends AnnotationSpecs)
  • ClassSpecs : ImportSpecs, FieldSpecs, AnnotationSpecs
  • FieldSpecs : AnnotationSpecs

Thus each ClassDoc object will result into a ClassSpecs object, that will feeds the code generation.

Further implementation of front controller/session

A kind of front controller and session data are required to implement #11 .

Such controller would :

  • be initialized with a set of xml description files (depending the workflow, i.e. a maven plugin could specify all the xml files of the project), that would constitute the processing session. Especially, one would have an index of any generated classes, to infer inheritance, and required code part to generate.
  • create and initialize any required processor/generator, passing appropriate session data. The lifecycle of processors and generators MUST be formalized.
  • call the processing for each beanset.
  • done

Generated classes import native types

When a field has a native type, e.g. boolean, the generated classes will import the native type and trigger a compilation error.

Native types must be removed from the import list.

Accessors are not following CamelCase

in the sample project, the generated code looks like :

package com.sporniket.sample.pojos;

import java.util.Date;
import java.util.List;

public abstract class SampleBasic
{

    private Date date ;
    private List<String> names ;

    public Date getdate() {return this.date ;}
    public void setdate(Date value) {this.date = value;}

    public List<String> getnames() {return this.names ;}
    public void setnames(List<String> value) {this.names = value;}

}

e.g. getdate() should be getDate().

The builder class does not compile, because it expects camel cases accessors.

[Bug] Escape string values for annotations parameters

When a field is annoted with @Pattern("\\d{5}")

Then the generated javabean field must be annoted with @Pattern("\\d{5}") instead of @Pattern("\d{5}")

Workaround

The POJO field is annoted with @Pattern("\\\\d{5}")

Do not add boundable and vetoable support code when not needed

For now, the generated classes contains code for managing bounded and vetoed properties, even if there is none.

  • do not add support for listener/fire event for bounded/vetoed properties if there is none
  • do not add property name if it is not boundable/vetoable

[seeg] implements compounded primary keys with @IdClass

When a primary key of an entity is made of several columns,

  • create an id class (IdOf[EntityName])
  • referenced by the entity class with the @javax.persistence.IdClass

An instance of id class will be immutable, and redefine the hashcode and equals using its components.

Allow to override fluent accessor in generated subclass

when generating a fluent accessor in a class, and generating a subclass, using the herited fluent accessor cannot be chained to another fluent accessor of the subclass.

allow something like :

<fluent name="xxx" type="yyy">

The name and type MUST obviously match the original definition for the code to be ok.

Class to process are not filtered against PojoSuffix

While mvn install the next version of the project (see acfd4de), the doclet tried :

Generating javabean null from com.sporniket.libre.javabeans.doclet.codespecs.ImportSpecs_Builder 

The build obviously failed.

The doclet MUST filter out the classes that does not have the pojoSuffix.

Support arrays fields

When there is the following declaration :

String[] refFields;

Then there is the following generated code :

    private String[] myRefFields ;

    public String[] getRefFields() {return myRefFields ;}
    public void setRefFields(String[] value) {myRefFields = value;}

Instead of the following generated code :

    private String myRefFields ;

    public String getRefFields() {return myRefFields ;}
    public void setRefFields(String value) {myRefFields = value;}

Copy javadoc comments - class and fields

Update 2019-09-19

  • While generating javabeans : convert pojo class names into javabeans class names.
  • While extracting pojo : copy as is.
  • field javadoc : copy to field, accessors and the fluent method in the builder class.

Update : in fact, javadoc annotations are not annotations in ClassDoc, look at comments and tags. see https://docs.oracle.com/javase/7/docs/jdk/api/javadoc/doclet/com/sun/javadoc/Doc.html


The javadoc class description is a special case of annotation for two reasons :

  • as a javadoc annotation, special case of annotation
  • as the annotation does not use a '@description' tag

The javadoc class description should be copied "as is" into the generated javabean code.

FIX windows path backslash problem

When running on windows, the backslash is used to escape characters instead of being used as is.

After processing the command line, replace any backslash by a double backslash.


It seems it is solvable using a groovy script that create a new variable with the expected value, and use it as the target path base :

            <!-- === Groovy hack to support windows pathes === -->
            <plugin>
                <groupId>org.codehaus.groovy.maven</groupId>
                <artifactId>gmaven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>set-unixy_build_directory!</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>execute</goal>
                        </goals>
                        <configuration>
                            <classpath>
                                <element>
                                    <groupId>commons-lang</groupId>
                                    <artifactId>commons-lang</artifactId>
                                    <version>2.4</version>
                                </element>
                            </classpath>
                            <source>
                                project.properties['mybuilddir'] =
                                project.build.directory.replace('\\','/');
                            </source>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- === code generation using the doclets === -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <executions>
                    <!-- === Javabeans generation === -->
                    <execution>
                        <!-- ... -->
                        <configuration>
                            <doclet>com.sporniket.libre.javabeans.doclet.ExpanderDoclet</doclet>
                            <!-- ... -->
                            <additionalOptions>
                                <additionalOption>-d</additionalOption>
                                <additionalOption>"${mybuilddir}/generated-classes/javabeans"</additionalOption>
                                <!-- ... -->
                            </additionalOptions>
                            <!-- ... -->
                        </configuration>
                    </execution>
                </executions>
            </plugin>

Extract javabean modelization and code generation

User story

As a developper

I want to have a separated javabean and builder generation code

In order to generate javabeans from other descriptions than POJO, e.g. from a database schema.

Technical details

  • The exchance format would be the json representation of a collection of ClassSpecs
  • Each generator (pojo, javabean, builder) would be adressable, and would be wrapped in a maven plugin

Wrong format for additionnal parameters in demo pom

The value of additionalOptions is not supported in some maven installation (I got a problem with Jenkins)

The value must be a collection of additionnalOption.

E.g. :

<additionalOptions>-d
  ${project.build.directory}/generated-classes/javabeans
-beanFieldPrefix ''</additionalOptions>

Should be rewritten as :

<additionalOptions>
    <additionalOption>-d</additionalOption>
    <additionalOption>"${project.build.directory}/generated-classes/javabeans"</additionalOption>
    <additionalOption>-beanFieldPrefix</additionalOption>
    <additionalOption>""</additionalOption>
</additionalOptions>

As a side effect, the pom will be more legible.

[seeg] Have a mapper from Entity to IdClass

When a table has a multi-column primary key, there is an id class.

  • Define a conversion method
//...
@IdClass(/*...*/)
class EntityThing {
  //...  
  public IdOfThing toIdClass() { return new IdOfThing(e.myKeyField1/*, ...*/) ; }
}

Allow generating abstract class

when creating a full class hierarchy, the base class cannot be abstract.

  • Add a boolean 'abstract' property to the 'Bean' tag

Collection/Map event names should be generated litterally

Redefining the suffixes (Foo.__EVENT_SUFFIX__ADD, Foo.__EVENT_SUFFIX__ADD_ALL,...) for use in each generated class is ugly.
Generate the names without using literral instead of storing the prefix in a separate static final field for use when initializing a property name for a managed collection/map event.

Copy simple class annotations and simple field annotations

Simple annotations are annotations that have no parameters (e.g. @Deprecated)

When generating javabean or extracting pojo, copy those simple annotations, using the simple name instead of the fully qualified name when possible.

Special case : @Deprecated annotations should be copied on the field, on the getter and on the setter.

[bug] Some annotation need to be generated on the accessors too

When a field is annoted like this : @JsonProperty("a_different_name") String altName

Then the generated javabean must have the annotation on the field AND the accessors

In order to get a correct JSON representation. (otherwise we get a field "a_different_name" and "altName")

Technical details

  • A registry of annotations that MUST be copied to the setter
  • A registry of annotations that MUST be copied to the getter
  • A registry of annotations that MUST NOT be copied to the field

Support annotation with parameters (esp. some jackson-annotations)

User Story

As sporniket-javabeans-doclet, I want to generate parametrized annotation
So that a developper is able to use jackson-annotations (@JsonProperty, @JsonTypeInfo and @JsonSubTypes)

Detailed Technical Specifications

Parameter name rules

  • The "value" parameter name is omitted, only the parameter value is generated
  • Otherwise the parameter name is generated followed by '=' and the parameter value

Parameter value rules

  • Literral values that are not class names are generated as is.
  • Enum values, constants, are imported to minimize value length.
  • Class names are processed to target generated classes if appliable

[bug][seeg]Generate only enums from the target schema

Use this request to get Postgresql enum values : 

SELECT 
 pg_namespace.nspname as schema,
 pg_type.typname AS enum_type, 
 pg_enum.enumlabel AS enum_value 
FROM pg_type 
JOIN pg_enum ON pg_enum.enumtypid = pg_type.oid 
JOIN pg_namespace ON pg_namespace.oid = pg_type.typnamespace
order by pg_enum.enumtypid, pg_enum.enumsortorder

and filter using the target schema.

Generate a builder that can handle a subclass

User Story

As a developper, I want to subclass a generated bean to add behaviors/method, and I want to be able to instanciate such enhanced javabeans using the builder, in order to avoid writing manually a duplicate of the generated builder for the base class.

Technical specification

Given the generated javabean A and its builder class A_Builder.

Then a regular javabean would be instancied like that : A myA = new A_Builder().with...()....done();.

Then a subclass B of the javabean would be instancied like that : B myB = (B) new A_Builder(new B()).with...().....done() ;

Generate a fluent Builder in a separate generator instead of generating fluent setters in the Javabeans

The current fluent setter generation has some flaws :

  • it can only generate fluent setters for the attribute directly declared in the class description
  • herited fluent setters breaks the chaining of calls (cannot access to the derived class fluent setters without casting...)
  • add bloat to an already bloated javabean.

Thus It may be more appropriate to remove the fluent api in the generated bean, and to generate a fluent Builder from an existing class, scanned using reflexion :

  • the generator process each class of a designated package (more on that latter)
  • If a class is abstract or is an interface, skip to the next one
  • If the class has no setter ("setXxx(...)"), skip to the next one
  • Generate a builder following the given pattern
public class MaStructureBuilder {
    private MaStructure maStructure = new MaStructure() ;

    public static final MaStructureBuilder builder() {
        return new MaStructureBuilder() ;
    }

    public build() {
        MaStructure result = maStructure ;
        maStructure = new MaStructure() ;
        return result ;
    }

    public void withXxx(XxxType value) {
        maStructure.setXxx(value);
        return this ;
    }

    //etc...
}

The generator will be instructed to scan some class using :

  • a list of specifically targeted classes
  • a list of packages
  • a list of specifically excluded classes
  • a list of regexp to exclude classes matched on their simple name
  • a list of regexp to exclude classse matched on their full name

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.