Skip to content

Commit

Permalink
[JAVA] Enumérations représentant totalement l'entité
Browse files Browse the repository at this point in the history
Fixes #373
  • Loading branch information
gideruette committed Nov 16, 2024
1 parent 074ca2d commit d94e3aa
Show file tree
Hide file tree
Showing 21 changed files with 417 additions and 203 deletions.
6 changes: 6 additions & 0 deletions TopModel.Generator.Jpa/GeneratorRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public void Register(IServiceCollection services, JpaConfig config, int number)
TrimSlashes(config, c => c.DtosPath);
TrimSlashes(config, c => c.EnumsPath);
TrimSlashes(config, c => c.ApiPath);
TrimSlashes(config, c => c.EnumConverterPath);
TrimSlashes(config, c => c.ResourcesPath);

config.Language ??= "java";
Expand All @@ -23,6 +24,11 @@ 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);
if (config.EnumsAsEnum)
{
services.AddGenerator<JpaConverterGenerator, JpaConfig>(config, number);
}

if (config.DaosPath != null)
{
services.AddGenerator<JpaDaoGenerator, JpaConfig>(config, number);
Expand Down
7 changes: 4 additions & 3 deletions TopModel.Generator.Jpa/JavaWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public void WriteAttribute(int indentLevel, string attributeName, params string[
/// <param name="modifier">Modifier.</param>
/// <param name="inheritedClass">Classe parente.</param>
/// <param name="implementingInterfaces">Interfaces implémentées.</param>
public void WriteClassDeclaration(string name, string? modifier, string? inheritedClass = null, IList<string>? implementingInterfaces = null)
/// <param name="classType">Class type (enum, class).</param>
public void WriteClassDeclaration(string name, string? modifier, string? inheritedClass = null, IList<string>? implementingInterfaces = null, string classType = "class")
{
if (string.IsNullOrEmpty(name))
{
Expand All @@ -86,11 +87,11 @@ public void WriteClassDeclaration(string name, string? modifier, string? inherit

if (string.IsNullOrEmpty(modifier))
{
sb.Append($"public class ");
sb.Append($"public {classType} ");
}
else
{
sb.Append($"public {modifier} class ");
sb.Append($"public {modifier} {classType} ");
}

sb.Append(name);
Expand Down
13 changes: 12 additions & 1 deletion TopModel.Generator.Jpa/JpaConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class JpaConfig : GeneratorConfigBase
/// </summary>
public string? DaosPath { get; set; }

/// <summary>
/// Localisation des DAOs, relative au répertoire de génération.
/// </summary>
public string? EnumConverterPath { get; set; } = "javagen:{app}/converters/{module}";

/// <summary>
/// Localisation des classses non persistées du modèle, relative au répertoire de génération. Par défaut, 'javagen/{app}/dtos/{module}'.
/// </summary>
Expand Down Expand Up @@ -59,6 +64,11 @@ public class JpaConfig : GeneratorConfigBase
/// </summary>
public bool EnumShortcutMode { get; set; }

/// <summary>
/// Option pour remplacer les classes de listes de références par des enums
/// </summary>
public bool EnumsAsEnum { get; set; }

/// <summary>
/// Nom du schéma sur lequel les entités sont sauvegardées
/// </summary>
Expand Down Expand Up @@ -170,7 +180,8 @@ public class JpaConfig : GeneratorConfigBase
nameof(DtosPath),
nameof(ApiPath),
nameof(EnumsPath),
nameof(DataFlowsPath)
nameof(DataFlowsPath),
nameof(EnumConverterPath)
];

public override bool CanClassUseEnums(Class classe, IEnumerable<Class>? availableClasses = null, IProperty? prop = null)
Expand Down
72 changes: 72 additions & 0 deletions TopModel.Generator.Jpa/JpaConverterGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Microsoft.Extensions.Logging;
using TopModel.Core;
using TopModel.Generator.Core;

namespace TopModel.Generator.Jpa;

/// <summary>
/// Générateur de DAOs JPA.
/// </summary>
public class JpaConverterGenerator : ClassGeneratorBase<JpaConfig>
{
private readonly ILogger<JpaConverterGenerator> _logger;

public JpaConverterGenerator(ILogger<JpaConverterGenerator> logger)
: base(logger)
{
_logger = logger;
}

public override string Name => "JpaConverterGen";

protected override bool FilterClass(Class classe)
{
return classe.IsPersistent && (!Config.UseJdbc || classe.PrimaryKey.Count() <= 1) && Config.CanClassUseEnums(classe) && Config.EnumsAsEnum;
}

protected override string GetFileName(Class classe, string tag)
{
string path = $"{classe.NamePascal}Converter.java";
return Path.Combine(
Config.OutputDirectory,
Config.ResolveVariables(Config.EnumConverterPath!, tag, module: classe.Namespace.Module).ToFilePath(),
path);
}

protected override void HandleClass(string fileName, Class classe, string tag)
{
var packageName = Config.ResolveVariables(
Config.EnumConverterPath!,
tag,
module: classe.Namespace.Module).ToPackageName();

using var fw = new JavaWriter(fileName, _logger, packageName, null);
fw.WriteLine();
fw.AddImport(classe.GetImport(Config, tag));
var javaOrJakarta = Config.PersistenceMode.ToString().ToLower();
fw.AddImport($"{javaOrJakarta}.persistence.AttributeConverter");
List<string> implements = new()
{
$"AttributeConverter<{classe.NamePascal}, String>"
};
fw.WriteClassDeclaration($"{classe.NamePascal}Converter", null, null, implements);

fw.WriteLine();
fw.WriteLine(1, "@Override");
fw.WriteLine(1, $@"public String convertToDatabaseColumn({classe.NamePascal} item) {{");
fw.WriteLine(2, $"return item == null ? null : item.get{classe.EnumKey.NamePascal}().name();");

Check warning on line 57 in TopModel.Generator.Jpa/JpaConverterGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 57 in TopModel.Generator.Jpa/JpaConverterGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
fw.WriteLine(1, "}");
WriteEnumEntityToAttribute(fw, classe);
fw.WriteLine("}");
}

private void WriteEnumEntityToAttribute(JavaWriter fw, Class classe)
{
fw.WriteLine();
fw.WriteLine(1, "@Override");
fw.WriteLine(1, $"public {classe.NamePascal} convertToEntityAttribute(String {classe.EnumKey!.NameCamel}) {{");
fw.WriteLine(2, $@"return {classe.NamePascal}.from({classe.EnumKey!.NameCamel});");

fw.WriteLine(1, $"}}");
}
}
2 changes: 1 addition & 1 deletion TopModel.Generator.Jpa/JpaDaoGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public JpaDaoGenerator(ILogger<JpaDaoGenerator> logger)

protected override bool FilterClass(Class classe)
{
return classe.IsPersistent && (!Config.UseJdbc || classe.PrimaryKey.Count() <= 1) && !Config.CanClassUseEnums(classe, Classes);
return classe.IsPersistent && (!Config.UseJdbc || classe.PrimaryKey.Count() <= 1) && !(Config.CanClassUseEnums(classe, Classes) && Config.EnumsAsEnum);
}

protected override string GetFileName(Class classe, string tag)
Expand Down
10 changes: 9 additions & 1 deletion TopModel.Generator.Jpa/JpaMapperGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,15 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla
}
else
{
getter = $"new {apTarget.Association.NamePascal}({sourceName}.{propertySource.NameByClassPascal.WithPrefix(getterPrefix)}())";
if (!Config.EnumsAsEnum)
{
getter = $"new {apTarget.Association.NamePascal}({sourceName}.{propertySource.NameByClassPascal.WithPrefix(getterPrefix)}())";
}
else
{
getter = $"{apTarget.Association.NamePascal}.from({sourceName}.{propertySource.NameByClassPascal.WithPrefix(getterPrefix)}())";
}

fw.AddImport(apTarget.Association.GetImport(Config, tag));
checkSourceNull = true;
}
Expand Down
10 changes: 5 additions & 5 deletions TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void WriteEnumConstructor(JavaWriter fw, Class classe, List<Class> availa
fw.WriteDocStart(1, "Enum constructor");
fw.WriteParam(classe.EnumKey!.NameCamel, "Code dont on veut obtenir l'instance");
fw.WriteDocEnd(1);
fw.WriteLine(1, $"public {classe.NamePascal}({_config.GetType(classe.EnumKey!)} {classe.EnumKey!.NameCamel}) {{");
fw.WriteLine(1, $"{(_config.EnumsAsEnum ? "private" : "public")} {classe.NamePascal}({_config.GetType(classe.EnumKey!)} {classe.EnumKey!.NameCamel}) {{");
if (classe.Extends != null || classe.Decorators.Any(d => _config.GetImplementation(d.Decorator)?.Extends is not null))
{
fw.WriteLine(2, $"super();");
Expand All @@ -35,7 +35,7 @@ public void WriteEnumConstructor(JavaWriter fw, Class classe, List<Class> availa
foreach (var refValue in classe.Values.OrderBy(x => x.Name, StringComparer.Ordinal))
{
var code = refValue.Value[codeProperty];
fw.WriteLine(2, $@"case {code} :");
fw.WriteLine(3, $@"case {code} :");
foreach (var prop in classe.GetProperties(availableClasses).Where(p => p != codeProperty))
{
var isString = _config.GetType(prop) == "String";
Expand All @@ -61,13 +61,13 @@ public void WriteEnumConstructor(JavaWriter fw, Class classe, List<Class> availa

var quote = isString ? "\"" : string.Empty;
var val = quote + value + quote;
fw.WriteLine(3, $@"this.{prop.NameByClassCamel} = {val};");
fw.WriteLine(4, $@"this.{prop.NameByClassCamel} = {val};");
}

fw.WriteLine(3, $@"break;");
fw.WriteLine(4, $@"break;");
}

fw.WriteLine(2, $@"}}");
fw.WriteLine(3, $@"}}");
}

fw.WriteLine(1, $"}}");
Expand Down
96 changes: 73 additions & 23 deletions TopModel.Generator.Jpa/JpaModelGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,35 +80,49 @@ protected override void HandleClass(string fileName, Class classe, string tag)

var implements = Config.GetClassImplements(classe).ToList();

if (!classe.IsPersistent)
if (!classe.IsPersistent && !(Config.EnumsAsEnum && Config.CanClassUseEnums(classe, AvailableClasses)))
{
implements.Add("Serializable");
fw.AddImport("java.io.Serializable");
}

fw.WriteClassDeclaration(classe.NamePascal, null, extends, implements);
var classType = Config.EnumsAsEnum && Config.CanClassUseEnums(classe, AvailableClasses) ? "enum" : "class";
fw.WriteClassDeclaration(classe.NamePascal, null, extends, implements, classType);

if (!classe.IsPersistent)
if (!classe.IsPersistent && !(Config.EnumsAsEnum && Config.CanClassUseEnums(classe, AvailableClasses)))
{
fw.WriteLine(" /** Serial ID */");
fw.WriteLine(1, "private static final long serialVersionUID = 1L;");
}

if (Config.CanClassUseEnums(classe, Classes))
{
fw.WriteLine();
var codeProperty = classe.EnumKey!;
var javaOrJakarta = Config.PersistenceMode.ToString().ToLower();
foreach (var refValue in classe.Values.OrderBy(x => x.Name, StringComparer.Ordinal))
if (!Config.EnumsAsEnum)
{
var code = refValue.Value[codeProperty];
if (classe.IsPersistent)
fw.WriteLine();
var codeProperty = classe.EnumKey!;
var javaOrJakarta = Config.PersistenceMode.ToString().ToLower();
foreach (var refValue in classe.Values.OrderBy(x => x.Name, StringComparer.Ordinal))
{
fw.AddImport($"{javaOrJakarta}.persistence.Transient");
fw.WriteLine(1, "@Transient");
}
var code = refValue.Value[codeProperty];
if (classe.IsPersistent)
{
fw.AddImport($"{javaOrJakarta}.persistence.Transient");
fw.WriteLine(1, "@Transient");
}

fw.WriteLine(1, $@"public static final {classe.NamePascal} {code} = new {classe.NamePascal}({Config.GetEnumName(codeProperty, classe)}.{code});");
fw.WriteLine(1, $@"public static final {classe.NamePascal} {code} = new {classe.NamePascal}({Config.GetEnumName(codeProperty, classe)}.{code});");
}
}
else if (Config.EnumsAsEnum)
{
var codeProperty = classe.EnumKey!;
var refValues = classe.Values.OrderBy(x => x.Name, StringComparer.Ordinal).ToList();
foreach (var refValue in refValues)
{
var code = refValue.Value[codeProperty];
fw.WriteLine(1, $@"{refValue.Name}({Config.GetEnumName(codeProperty, classe)}.{code}){(refValues.IndexOf(refValue) == refValues.Count - 1 ? ";" : ",")}");
}
}
}

Expand All @@ -118,11 +132,11 @@ protected override void HandleClass(string fileName, Class classe, string tag)
JpaModelPropertyGenerator.WriteCompositePrimaryKeyClass(fw, classe, tag);
}

if (Config.CanClassUseEnums(classe, Classes)
|| Config.MappersInClass && classe.FromMappers.Any(c => c.ClassParams.All(p => AvailableClasses.Contains(p.Class)))
if (Config.CanClassUseEnums(classe, Classes) && !Config.EnumsAsEnum
|| Config.MappersInClass && classe.FromMappers.Exists(c => c.ClassParams.All(p => AvailableClasses.Contains(p.Class)))
|| classe.Extends != null
|| AvailableClasses.Any(c => c.Extends == classe)
|| classe.Decorators.Any(d => Config.GetImplementation(d.Decorator)?.Extends is not null))
|| AvailableClasses.Exists(c => c.Extends == classe)
|| classe.Decorators.Exists(d => Config.GetImplementation(d.Decorator)?.Extends is not null))
{
JpaModelConstructorGenerator.WriteNoArgConstructor(fw, classe);
}
Expand All @@ -137,8 +151,17 @@ protected override void HandleClass(string fileName, Class classe, string tag)
JpaModelConstructorGenerator.WriteEnumConstructor(fw, classe, AvailableClasses, tag, _modelConfig);
}

if (Config.CanClassUseEnums(classe, Classes))
{
WriteEnumFrom(fw, classe);
}

WriteGetters(fw, classe, tag);
WriteSetters(fw, classe, tag);
if (!(Config.EnumsAsEnum && Config.CanClassUseEnums(classe, AvailableClasses)))
{
WriteSetters(fw, classe, tag);
}

if (!Config.UseJdbc)
{
WriteAdders(fw, classe, tag);
Expand Down Expand Up @@ -205,7 +228,7 @@ private void WriteAnnotations(JavaWriter fw, Class classe, string tag)
fw.WriteLine("@Generated(\"TopModel : https://github.com/klee-contrib/topmodel\")");
}

if (classe.IsPersistent)
if (classe.IsPersistent && !(Config.EnumsAsEnum && Config.CanClassUseEnums(classe, AvailableClasses)))
{
if (Config.UseJdbc)
{
Expand Down Expand Up @@ -290,8 +313,35 @@ private void WriteAnnotations(JavaWriter fw, Class classe, string tag)

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

private void WriteEnumFrom(JavaWriter fw, Class classe)
{
var codeProperty = classe.EnumKey!;
fw.WriteLine();
fw.WriteLine(1, $"public static {classe.NamePascal} from(String {classe.EnumKey!.NameCamel}) {{");
fw.WriteLine(2, $"return from({Config.GetType(codeProperty)}.valueOf({classe.EnumKey!.NameCamel}));");
fw.WriteLine(1, $"}}");

fw.WriteLine();
fw.WriteLine(1, $"public static {classe.NamePascal} from({Config.GetType(codeProperty)} {classe.EnumKey!.NameCamel}) {{");
fw.WriteLine(2, $@"switch({classe.EnumKey!.NameCamel}) {{");
foreach (var refValue in classe.Values.OrderBy(x => x.Name, StringComparer.Ordinal))
{
var code = refValue.Value[codeProperty];
fw.WriteLine(3, $@"case {code}:");
fw.WriteLine(4, $@"return {refValue.Name};");
}

fw.WriteLine(3, $@"default:");
fw.AddImport("java.util.NoSuchElementException");
fw.WriteLine(4, $@"throw new NoSuchElementException({classe.EnumKey!.NameCamel} + "" value unrecognized"");");

fw.WriteLine(2, "}");

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

private void WriteEnumShortcuts(JavaWriter fw, Class classe, string tag)
Expand Down Expand Up @@ -490,13 +540,13 @@ private void WriteSetters(JavaWriter fw, Class classe, string tag)

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

foreach (var toMapper in toMappers)
{
var (clazz, mapper) = toMapper;
var mapper = toMapper.mapper;

fw.WriteLine();
fw.WriteDocStart(1, $"Mappe '{classe}' vers '{mapper.Class.NamePascal}'");
Expand Down
Loading

0 comments on commit d94e3aa

Please sign in to comment.