Skip to content

Commit

Permalink
Fix #373 : [JAVA] Enumérations représentant totalement l'entité #373
Browse files Browse the repository at this point in the history
  • Loading branch information
gideruette committed Nov 13, 2024
1 parent 96d11d5 commit 38506b3
Show file tree
Hide file tree
Showing 14 changed files with 532 additions and 94 deletions.
7 changes: 7 additions & 0 deletions TopModel.Generator.Jpa/GeneratorRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ public class GeneratorRegistration : IGeneratorRegistration<JpaConfig>
/// <inheritdoc cref="IGeneratorRegistration{T}.Register" />
public void Register(IServiceCollection services, JpaConfig config, int number)
{
if (config.EnumsValuesPath == "default")
{
config.EnumsValuesPath = config.EnumsPath;
}

TrimSlashes(config, c => c.EntitiesPath);
TrimSlashes(config, c => c.DaosPath);
TrimSlashes(config, c => c.DtosPath);
TrimSlashes(config, c => c.EnumsPath);
TrimSlashes(config, c => c.EnumsValuesPath);
TrimSlashes(config, c => c.ApiPath);
TrimSlashes(config, c => c.ResourcesPath);

Expand All @@ -23,6 +29,7 @@ public void Register(IServiceCollection services, JpaConfig config, int number)
services.AddGenerator<JpaModelInterfaceGenerator, JpaConfig>(config, number);
services.AddGenerator<JpaMapperGenerator, JpaConfig>(config, number);
services.AddGenerator<JpaEnumGenerator, JpaConfig>(config, number);
services.AddGenerator<JpaEnumValueGenerator, JpaConfig>(config, number);
if (config.DaosPath != null)
{
services.AddGenerator<JpaDaoGenerator, JpaConfig>(config, number);
Expand Down
27 changes: 26 additions & 1 deletion TopModel.Generator.Jpa/JpaConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ public class JpaConfig : GeneratorConfigBase
public string EntitiesPath { get; set; } = "javagen:{app}/entities/{module}";

/// <summary>
/// Localisation des classes persistées du modèle, relative au répertoire de génération. Par défaut, 'javagen/{app}/entities/{module}'.
/// Localisation des enums, relative au répertoire de génération. Par défaut, 'javagen:{app}/enums/{module}'.
/// </summary>
public string EnumsPath { get; set; } = "javagen:{app}/enums/{module}";

/// <summary>
/// Localisation des enums de valeurs, relative au répertoire de génération. Par défaut, 'javagen:{app}/enums/{module}'.
/// </summary>
public string EnumsValuesPath { get; set; } = "default";

/// <summary>
/// Localisation des DAOs, relative au répertoire de génération.
/// </summary>
Expand Down Expand Up @@ -158,6 +163,7 @@ public class JpaConfig : GeneratorConfigBase
nameof(DtosPath),
nameof(ApiPath),
nameof(EnumsPath),
nameof(EnumsValuesPath),
nameof(ApiGeneration),
nameof(ResourcesPath),
nameof(DbSchema)
Expand All @@ -170,6 +176,7 @@ public class JpaConfig : GeneratorConfigBase
nameof(DtosPath),
nameof(ApiPath),
nameof(EnumsPath),
nameof(EnumsValuesPath),
nameof(DataFlowsPath)
];

Expand Down Expand Up @@ -232,6 +239,14 @@ public string GetEnumFileName(IProperty property, Class classe, string tag)
$"{GetEnumName(property, classe)}.java");
}

public string GetEnumValueFileName(IProperty property, Class classe, string tag)
{
return Path.Combine(
OutputDirectory,
ResolveVariables(EnumsValuesPath, tag, module: classe.Namespace.Module).ToFilePath(),
$"{classe.NamePascal}_Value.java");
}

public string GetEnumName(IProperty property, Class classe)
{
return $"{classe.NamePascal}{property.Name.ToPascalCase()}";
Expand All @@ -242,6 +257,11 @@ public string GetEnumPackageName(Class classe, string tag)
return GetPackageName(classe.Namespace, EnumsPath, tag);
}

public string GetEnumValuePackageName(Class classe, string tag)
{
return GetPackageName(classe.Namespace, EnumsValuesPath, tag);
}

public string GetMapperFilePath((Class Classe, FromMapper Mapper) mapper, string tag)
{
var (ns, modelPath) = GetMapperLocation(mapper);
Expand Down Expand Up @@ -333,4 +353,9 @@ protected override bool IsEnumNameValid(string name)
{
return base.IsEnumNameValid(name) && !Regex.IsMatch(name ?? string.Empty, "(?<=[^$\\w'\"\\])(?!(abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|double|do|else|enum|extends|false|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|native|new|null|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|transient|true|try|void|volatile|while|_\\b))([A-Za-z_$][$\\w]*)");
}

public bool IsEnumNameJavaValid(string name)

Check warning on line 357 in TopModel.Generator.Jpa/JpaConfig.cs

View workflow job for this annotation

GitHub Actions / build

Check warning on line 357 in TopModel.Generator.Jpa/JpaConfig.cs

View workflow job for this annotation

GitHub Actions / build

{
return IsEnumNameValid(name);
}
}
213 changes: 213 additions & 0 deletions TopModel.Generator.Jpa/JpaEnumValueGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
using Microsoft.Extensions.Logging;
using TopModel.Core;
using TopModel.Core.FileModel;
using TopModel.Generator.Core;
using TopModel.Utils;

namespace TopModel.Generator.Jpa;

/// <summary>
/// Générateur de fichiers de modèles JPA.
/// </summary>
public class JpaEnumValueGenerator : GeneratorBase<JpaConfig>

Check warning on line 12 in TopModel.Generator.Jpa/JpaEnumValueGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Les éléments de la classe ne sont pas dans le bon ordre

Check warning on line 12 in TopModel.Generator.Jpa/JpaEnumValueGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Les éléments de la classe ne sont pas dans le bon ordre
{
private readonly ILogger<JpaEnumValueGenerator> _logger;

public JpaEnumValueGenerator(ILogger<JpaEnumValueGenerator> logger, ModelConfig modelConfig)
: base(logger)
{
_logger = logger;
}

public override string Name => "JpaEnumValuesGen";

public override IEnumerable<string> GeneratedFiles => Files
.Values
.SelectMany(f => f.Classes.Where(FilterClass))
.SelectMany(c => Config.Tags.Intersect(c.Tags).SelectMany(tag => GetEnumProperties(c).Select(p => GetFileName(p, c, tag)))).Distinct();

protected bool FilterClass(Class classe)
{
return !classe.Abstract
&& Config.CanClassUseEnums(classe, Classes.ToList())
&& GetAllValues(classe).All(v => Config.IsEnumNameJavaValid(v.Name));
}

protected string GetFileName(IProperty property, Class classe, string tag)
{
return Config.GetEnumValueFileName(property, classe, tag);
}

protected void HandleClass(Class classe, string tag)
{
foreach (var p in GetEnumProperties(classe))
{
WriteEnum(p, classe, tag);
}
}

protected override void HandleFiles(IEnumerable<ModelFile> files)
{
foreach (var file in files)
{
foreach (var classe in file.Classes.Where(FilterClass))
{
foreach (var tag in Config.Tags.Intersect(classe.Tags))
{
HandleClass(classe, tag);
}
}
}
}

private IEnumerable<IProperty> GetEnumProperties(Class classe)
{
List<IProperty> result = new();
if (classe.EnumKey != null && Config.CanClassUseEnums(classe, prop: classe.EnumKey) && !(classe.Extends != null && Config.CanClassUseEnums(classe.Extends, Classes, prop: classe.EnumKey)))
{
result.Add(classe.EnumKey);
}

var uks = classe.UniqueKeys.Where(uk => uk.Count == 1 && Config.CanClassUseEnums(classe, Classes, uk.Single()) && !(classe.Extends != null && Config.CanClassUseEnums(classe.Extends, Classes, prop: classe.EnumKey))).Select(uk => uk.Single());
result.AddRange(uks);
return result;
}

private void WriteEnum(IProperty property, Class classe, string tag)
{
var packageName = Config.GetEnumValuePackageName(classe, tag);
using var fw = new JavaWriter(Config.GetEnumValueFileName(property, classe, tag), _logger, packageName, null);
fw.WriteLine();
var codeProperty = classe.EnumKey!;
fw.WriteDocStart(0, $"Enumération des valeurs possibles de la classe {classe.NamePascal}");
fw.WriteDocEnd(0);
fw.WriteLine($@"public enum {classe.NamePascal}_Value {{");
var i = 0;

var refs = GetAllValues(classe)
.ToList();

foreach (var refValue in refs)
{
if (i > 0)
{
fw.WriteLine();
}

i++;
var isLast = i == refs.Count();
if (classe.DefaultProperty != null)
{
fw.WriteDocStart(1, $"{refValue.Value[classe.DefaultProperty]}");
fw.WriteDocEnd(1);
}

List<string> enumAsString = [$"{refValue.Name.ToConstantCase()}("];
foreach (var prop in classe.Properties)
{
var isString = Config.GetType(prop) == "String";
var isInt = Config.GetType(prop) == "int";
var isBoolean = Config.GetType(prop) == "Boolean";
var value = refValue.Value.ContainsKey(prop) ? refValue.Value[prop] : "null";

if (prop is AssociationProperty ap && ap.Association.Values.Any(r => r.Value.ContainsKey(ap.Property) && r.Value[ap.Property] == value))
{
fw.AddImport($"{Config.GetEnumValuePackageName(ap.Association.EnumKey!.Class, tag)}.{ap.Association.NamePascal}_Value");
value = ap.Association.NamePascal + "_Value." + value;
isString = false;
}
else if (Config.CanClassUseEnums(classe, prop: prop))
{
value = Config.GetType(prop) + "." + value;
}

if (Config.TranslateReferences == true && classe.DefaultProperty == prop && !Config.CanClassUseEnums(classe, prop: prop))
{
value = refValue.ResourceKey;
}

var quote = isString ? "\"" : string.Empty;
var val = quote + value + quote;
enumAsString.Add($@"{val}{(prop == classe.Properties.Last() ? string.Empty : ", ")}");
}

enumAsString.Add($"){(isLast ? ";" : ",")} ");
fw.WriteLine(1, enumAsString.Aggregate(string.Empty, (acc, curr) => acc + curr));
}

foreach (var prop in classe.Properties)
{
fw.WriteLine();
fw.WriteDocStart(1, $@"{prop.NameByClassPascal}");
fw.WriteDocEnd(1);
var fieldName = prop.NameByClassCamel;
if (prop is AssociationProperty ap)
{
fieldName = $"{ap.NameByClassCamel}Value";
fw.WriteLine(1, $@"private final {ap.Association.NamePascal}_Value {fieldName};");
}
else
{
fw.WriteLine(1, $@"private final {Config.GetType(prop)} {fieldName};");
}
}

WriteConstructor(classe, fw, classe.Properties);

foreach (var prop in classe.Properties)
{
fw.WriteLine();
var fieldName = prop.NameByClassCamel;
fw.WriteDocStart(1, $"Getter for {fieldName}");
fw.WriteDocEnd(1);
if (prop is AssociationProperty ap)
{
fieldName = $"{ap.NameByClassCamel}Value";
fw.WriteLine(1, $@"public {ap.Association.NamePascal}_Value get{fieldName.ToFirstUpper()}() {{");
}
else
{
fw.WriteLine(1, $@"public {Config.GetType(prop)} get{fieldName.ToFirstUpper()}() {{");
}

fw.WriteLine(2, $@"return this.{fieldName};");
fw.WriteLine(1, $@"}}");
}

fw.WriteLine("}");
}

private void WriteConstructor(Class classe, JavaWriter fw, IEnumerable<IProperty> properties)
{
// Constructeur
fw.WriteDocStart(1, "Enum constructor");
fw.WriteDocEnd(1);
string constructorAsString =
$@"{classe.NamePascal}_Value(" +
string.Join(", ", properties.Select((prop, index) =>
{
var fieldName = prop.NameByClassCamel;
if (prop is AssociationProperty ap)
{
fieldName = $"{ap.NameByClassCamel}Value";
return $@"final {ap.Association.NamePascal}_Value {fieldName}";
}

return $@"final {Config.GetType(prop)} {fieldName}";
})) + "){";
fw.WriteLine(1, constructorAsString);
foreach (var prop in properties)
{
var fieldName = prop.NameByClassCamel;
if (prop is AssociationProperty ap)
{
fieldName = $"{ap.NameByClassCamel}Value";
}

// Constructeur set
fw.WriteLine(2, $@" this.{fieldName} = {fieldName};");
}

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

0 comments on commit 38506b3

Please sign in to comment.