Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JPA] Big Bang : simplification et séparation des générateurs (pour faciliter les futures évols) #410

Merged
merged 5 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ jobs:
dotnet-version: 9.0.x

- name: build
run: dotnet build -f net8.0
run: dotnet build -f net9.0

- name: modgen
run: dotnet run --project TopModel.Generator/TopModel.Generator.csproj -f net8.0 -- -c
run: dotnet run --project TopModel.Generator/TopModel.Generator.csproj -f net9.0 -- -c

- name: tmdgen
run: dotnet run --project TopModel.ModelGenerator/TopModel.ModelGenerator.csproj -f net8.0 -- -f samples/generators/open-api/tmdgen.config -c
run: dotnet run --project TopModel.ModelGenerator/TopModel.ModelGenerator.csproj -f net9.0 -- -f samples/generators/open-api/tmdgen.config -c

- name: Set up JDK 21
uses: actions/setup-java@v4
Expand Down
20 changes: 4 additions & 16 deletions TopModel.Generator.Core/GeneratorConfigBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,14 @@ public IEnumerable<string> GetDecoratorImports(Endpoint endpoint, string tag)
.Distinct();
}

public IEnumerable<string> GetDomainAnnotations(IProperty property, string tag)
public IEnumerable<(string Annotation, IEnumerable<string> Imports)> GetDomainAnnotations(IProperty property, string tag)
{
if (property.Domain is not null)
{
foreach (var annotation in GetImplementation(property.Domain)!.Annotations
.Where(a => FilterAnnotations(a, property, tag))
.Select(a => a.Text.ParseTemplate(property, this, tag)))
.Where(a => FilterAnnotations(a, property, tag)))
{
yield return annotation;
yield return (Annotation: annotation.Text.ParseTemplate(property, this, tag), Imports: annotation.Imports.Select(i => i.ParseTemplate(property, this, tag)));
}
}
}
Expand All @@ -206,21 +205,10 @@ public IEnumerable<string> GetDomainImports(IProperty property, string tag)
yield return import;
}

foreach (var import in GetImplementation(property.Domain)!.Annotations
.Where(a => FilterAnnotations(a, property, tag))
.SelectMany(a => a.Imports)
.Select(u => u.ParseTemplate(property, this, tag)))
foreach (var import in GetDomainAnnotations(property, tag).SelectMany(a => a.Imports))
{
yield return import;
}

var op = property switch
{
AssociationProperty ap => ap.Property,
AliasProperty { OriginalProperty: AssociationProperty ap } => ap.Property,
AliasProperty alp => alp.OriginalProperty,
_ => property
};
}
}

Expand Down
4 changes: 2 additions & 2 deletions TopModel.Generator.Csharp/CSharpClassGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ protected virtual void GenerateProperty(CSharpWriter w, IProperty property, Hash
&& !sameColumnSet.Contains(property.SqlName))
{
var sqlName = Config.UseLowerCaseSqlNames ? property.SqlName.ToLower() : property.SqlName;
if (!Config.GetDomainAnnotations(property, tag).Any(a => a.TrimStart('[').StartsWith("Column")))
if (!Config.GetDomainAnnotations(property, tag).Any(a => a.Annotation.TrimStart('[').StartsWith("Column")))
{
w.WriteAttribute(1, "Column", $@"""{sqlName}""");
}
Expand Down Expand Up @@ -404,7 +404,7 @@ protected virtual void GenerateProperty(CSharpWriter w, IProperty property, Hash

foreach (var annotation in Config.GetDomainAnnotations(property, tag))
{
w.WriteAttribute(1, annotation);
w.WriteAttribute(1, annotation.Annotation);
}

if (Config.IsPersistent(property.Class, tag) && property is AssociationProperty { Type: AssociationType.OneToMany or AssociationType.ManyToMany })
Expand Down
7 changes: 7 additions & 0 deletions TopModel.Generator.Jpa/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 1.1.0

Breaking changes :
- Suppression du mode `enumShortcut`
- Les DAO des listes de références ne sont plus générés. La première génération risque de les supprimer
- Annuler la suppression des DAO utilisés. Normalement, il y en a peu, d'où la suppression de la génération automatique...

## 1.0.11
- [d31beb](https://github.com/klee-contrib/topmodel/commit/d31beb5e0d42178e62f6b19316abcbbccde8884d) Fix Initialisation enum dans le cas d'alias ou d'association : cas null

Expand Down
13 changes: 12 additions & 1 deletion TopModel.Generator.Jpa/GeneratorRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ public void Register(IServiceCollection services, JpaConfig config, int number)

config.Language ??= "java";

services.AddGenerator<JpaModelGenerator, JpaConfig>(config, number);
services.AddGenerator<JavaDtoGenerator, JpaConfig>(config, number);
if (config.UseJdbc)
{
services.AddGenerator<JdbcEntityGenerator, JpaConfig>(config, number);
}
else
{
services.AddGenerator<JpaEnumEntityGenerator, JpaConfig>(config, number);
services.AddGenerator<JavaEnumDtoGenerator, JpaConfig>(config, number);
services.AddGenerator<JpaEntityGenerator, JpaConfig>(config, number);
}

services.AddGenerator<JpaModelInterfaceGenerator, JpaConfig>(config, number);
services.AddGenerator<JpaMapperGenerator, JpaConfig>(config, number);
services.AddGenerator<JpaEnumGenerator, JpaConfig>(config, number);
Expand Down
20 changes: 0 additions & 20 deletions TopModel.Generator.Jpa/ImportsJpaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,6 @@ public static string GetImport(this Class classe, JpaConfig config, string tag)
return $"{config.GetPackageName(classe, config.GetBestClassTag(classe, tag))}.{classe.NamePascal}";
}

public static List<string> GetImports(this Class classe, JpaConfig config, string tag, IEnumerable<Class> availableClasses)
{
var imports = new List<string>();

if (classe.Extends != null)
{
imports.Add(classe.GetImport(config, config.GetBestClassTag(classe, tag)));
}

if (config.MappersInClass)
{
imports
.AddRange(classe.FromMappers.Where(fm => fm.ClassParams.All(fmp => availableClasses.Contains(fmp.Class))).SelectMany(fm => fm.ClassParams).Select(fmp => fmp.Class.GetImport(config, tag)));
imports
.AddRange(classe.ToMappers.Where(tm => availableClasses.Contains(tm.Class)).Select(fmp => fmp.Class.GetImport(config, config.GetBestClassTag(classe, tag))));
}

return imports;
}

public static List<string> GetKindImports(this CompositionProperty cp, JpaConfig config, string tag)
{
return config.GetDomainImports(cp, config.GetBestClassTag(cp.Composition, tag)).ToList();
Expand Down
73 changes: 73 additions & 0 deletions TopModel.Generator.Jpa/JavaAnnotation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
namespace TopModel.Generator.Jpa;

Check warning on line 1 in TopModel.Generator.Jpa/JavaAnnotation.cs

View workflow job for this annotation

GitHub Actions / build


public class JavaAnnotation
{
public JavaAnnotation(string name, string import)
{
Name = name.Trim('@');
Imports = [import];
}

public JavaAnnotation(string name, IEnumerable<string> imports)
{
Name = name.Trim('@');
Imports.AddRange(imports);
}

public JavaAnnotation(string name, string value, string import)
{
Name = name.Trim('@');
Imports = [import];
Attributes.Add(("value", value));
}

public string Name { get; set; }

public List<string> Imports { get; set; } = new();

private List<(string Name, object Value)> Attributes { get; } = new();

public JavaAnnotation AddAttribute(string name, string value, string import)
{
Attributes.Add((name, value));
Imports.Add(import);
return this;
}

public JavaAnnotation AddAttribute(string name, string value)
{
Attributes.Add((name, value));
return this;
}

public JavaAnnotation AddAttribute(string value)
{
Attributes.Add(("value", value));
return this;
}

public JavaAnnotation AddAttribute(string name, JavaAnnotation value)
{
Attributes.Add((name, value));
Imports.AddRange(value.Imports);
return this;
}

public override string ToString()
{
var name = Name.StartsWith('@') ? Name : $"@{Name}";
if (!Attributes.Any())
{
return name;
}
else if (Attributes.Count() == 1 && Attributes.Any(a => a.Name == "value"))
{
return $"{name}({Attributes.First().Value})";
}
else
{
var attributes = string.Join(", ", Attributes.Select(a => $"{a.Name} = {a.Value}"));
return $"{name}({attributes})";
}
}
}
175 changes: 175 additions & 0 deletions TopModel.Generator.Jpa/JavaClassGeneratorBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using Microsoft.Extensions.Logging;

Check warning on line 1 in TopModel.Generator.Jpa/JavaClassGeneratorBase.cs

View workflow job for this annotation

GitHub Actions / build

using TopModel.Core;
using TopModel.Core.Model.Implementation;
using TopModel.Generator.Core;
using TopModel.Utils;

namespace TopModel.Generator.Jpa;

/// <summary>
/// Générateur de fichiers de modèles JPA.
/// </summary>
public abstract class JavaClassGeneratorBase : ClassGeneratorBase<JpaConfig>
{
private JavaConstructorGenerator? _jpaModelConstructorGenerator;
private JpaModelPropertyGenerator? _jpaModelPropertyGenerator;

public JavaClassGeneratorBase(ILogger<JavaClassGeneratorBase> logger)
: base(logger)
{
}

protected static Dictionary<string, string> NewableTypes => new()
{
["List"] = "ArrayList",
["Set"] = "HashSet"
};

protected string JavaxOrJakarta => Config.PersistenceMode.ToString().ToLower();

protected virtual JavaConstructorGenerator ConstructorGenerator
{
get
{
_jpaModelConstructorGenerator ??= new JavaConstructorGenerator(Config);
return _jpaModelConstructorGenerator;
}
}

protected JpaModelPropertyGenerator JpaModelPropertyGenerator
{
get
{
_jpaModelPropertyGenerator ??= new JpaModelPropertyGenerator(Config, Classes, NewableTypes);
return _jpaModelPropertyGenerator;
}
}

protected virtual void WriteAnnotations(JavaWriter fw, Class classe, string tag)
{
fw.WriteDocStart(0, classe.Comment);
fw.WriteDocEnd(0);
if (Config.GeneratedHint)
{
fw.AddImport($"{JavaxOrJakarta}.annotation.Generated");
fw.WriteLine("@Generated(\"TopModel : https://github.com/klee-contrib/topmodel\")");
}

fw.AddImports(Config.GetDecoratorImports(classe, tag).ToList());
foreach (var a in Config.GetDecoratorAnnotations(classe, tag))
{
fw.WriteLine($"{(a.StartsWith("@") ? string.Empty : "@")}{a}");
}
}

protected void WriteFieldsEnum(JavaWriter fw, Class classe, string tag)
{
if (!classe.Properties.Any())
{
return;
}

if (Config.FieldsEnumInterface != null)
{
fw.AddImport(Config.FieldsEnumInterface.Replace("<>", string.Empty));
}

fw.WriteLine();
fw.WriteDocStart(1, $"Enumération des champs de la classe {{@link {classe.GetImport(Config, tag)} {classe.NamePascal}}}");
fw.WriteDocEnd(1);
string enumDeclaration = @$"public enum Fields ";
if (Config.FieldsEnumInterface != null)
{
enumDeclaration += $"implements {Config.FieldsEnumInterface.Split(".").Last().Replace("<>", $"<{classe.NamePascal}>")}";
}

enumDeclaration += " {";
fw.WriteLine(1, enumDeclaration);

var props = classe.GetProperties(Classes).Select(prop =>
{
string name;
if (prop is AssociationProperty ap && ap.Association.IsPersistent && !Config.UseJdbc)
{
name = ap.NameByClassCamel.ToConstantCase();
}
else
{
name = prop.NameCamel.ToConstantCase();
}

var javaType = Config.GetType(prop, useClassForAssociation: classe.IsPersistent && !Config.UseJdbc && prop is AssociationProperty asp && asp.Association.IsPersistent);
javaType = javaType.Split("<")[0];
return $" {name}({javaType}.class)";
});

fw.WriteLine(string.Join(", //\n", props) + ";");

fw.WriteLine();

fw.WriteLine(2, "private final Class<?> type;");
fw.WriteLine();
fw.WriteLine(2, "Fields(Class<?> type) {");
fw.WriteLine(3, "this.type = type;");
fw.WriteLine(2, "}");

fw.WriteLine();

fw.WriteLine(2, "public Class<?> getType() {");
fw.WriteLine(3, "return this.type;");
fw.WriteLine(2, "}");

fw.WriteLine(1, "}");
}

protected virtual void WriteGetters(JavaWriter fw, Class classe, string tag)
{
foreach (var property in classe.GetProperties(Classes))
{
JpaModelPropertyGenerator.WriteGetter(fw, tag, property);
}
}

protected virtual void WriteSetters(JavaWriter fw, Class classe, string tag)
{
foreach (var property in classe.GetProperties(Classes))
{
JpaModelPropertyGenerator.WriteSetter(fw, tag, property);
}
}

protected void WriteToMappers(JavaWriter fw, Class classe, string tag)
{
var toMappers = classe.ToMappers.Where(p => Classes.Contains(p.Class)).Select(m => (classe, m))
.OrderBy(m => m.m.Name)
.ToList();

foreach (var toMapper in toMappers)
{
var (clazz, mapper) = toMapper;
fw.AddImport(mapper.Class.GetImport(Config, tag));
fw.WriteLine();
fw.WriteDocStart(1, $"Mappe '{classe}' vers '{mapper.Class.NamePascal}'");
if (mapper.Comment != null)
{
fw.WriteLine(1, $" * {mapper.Comment}");
}

fw.WriteParam("target", $"Instance pré-existante de '{mapper.Class.NamePascal}'. Une nouvelle instance sera créée si non spécifié.");
fw.WriteReturns(1, $"Une instance de '{mapper.Class.NamePascal}'");

fw.WriteDocEnd(1);
var (mapperNs, mapperModelPath) = Config.GetMapperLocation(toMapper);

fw.WriteLine(1, $"public {mapper.Class.NamePascal} {mapper.Name.Value.ToCamelCase()}({mapper.Class.NamePascal} target) {{");
fw.WriteLine(2, $"return {Config.GetMapperName(mapperNs, mapperModelPath)}.{mapper.Name.Value.ToCamelCase()}(this, target);");
fw.AddImport(Config.GetMapperImport(mapperNs, mapperModelPath, tag)!);
fw.WriteLine(1, "}");

if (toMappers.IndexOf(toMapper) < toMappers.Count - 1)
{
fw.WriteLine();
}
}
}
}
Loading
Loading