diff --git a/TopModel.Generator.Jpa/GeneratorRegistration.cs b/TopModel.Generator.Jpa/GeneratorRegistration.cs index 82c73edc..83e46f19 100644 --- a/TopModel.Generator.Jpa/GeneratorRegistration.cs +++ b/TopModel.Generator.Jpa/GeneratorRegistration.cs @@ -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"; @@ -23,6 +24,11 @@ public void Register(IServiceCollection services, JpaConfig config, int number) services.AddGenerator(config, number); services.AddGenerator(config, number); services.AddGenerator(config, number); + if (config.EnumsAsEnum) + { + services.AddGenerator(config, number); + } + if (config.DaosPath != null) { services.AddGenerator(config, number); diff --git a/TopModel.Generator.Jpa/JavaWriter.cs b/TopModel.Generator.Jpa/JavaWriter.cs index c940c5ee..c97c81ca 100644 --- a/TopModel.Generator.Jpa/JavaWriter.cs +++ b/TopModel.Generator.Jpa/JavaWriter.cs @@ -75,7 +75,8 @@ public void WriteAttribute(int indentLevel, string attributeName, params string[ /// Modifier. /// Classe parente. /// Interfaces implémentées. - public void WriteClassDeclaration(string name, string? modifier, string? inheritedClass = null, IList? implementingInterfaces = null) + /// Class type (enum, class). + public void WriteClassDeclaration(string name, string? modifier, string? inheritedClass = null, IList? implementingInterfaces = null, string classType = "class") { if (string.IsNullOrEmpty(name)) { @@ -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); diff --git a/TopModel.Generator.Jpa/JpaConfig.cs b/TopModel.Generator.Jpa/JpaConfig.cs index cda9e144..04031761 100644 --- a/TopModel.Generator.Jpa/JpaConfig.cs +++ b/TopModel.Generator.Jpa/JpaConfig.cs @@ -24,6 +24,11 @@ public class JpaConfig : GeneratorConfigBase /// public string? DaosPath { get; set; } + /// + /// Localisation des DAOs, relative au répertoire de génération. + /// + public string? EnumConverterPath { get; set; } = "javagen:{app}/converters/{module}"; + /// /// Localisation des classses non persistées du modèle, relative au répertoire de génération. Par défaut, 'javagen/{app}/dtos/{module}'. /// @@ -59,6 +64,11 @@ public class JpaConfig : GeneratorConfigBase /// public bool EnumShortcutMode { get; set; } + /// + /// Option pour remplacer les classes de listes de références par des enums + /// + public bool EnumsAsEnum { get; set; } + /// /// Nom du schéma sur lequel les entités sont sauvegardées /// @@ -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? availableClasses = null, IProperty? prop = null) diff --git a/TopModel.Generator.Jpa/JpaConverterGenerator.cs b/TopModel.Generator.Jpa/JpaConverterGenerator.cs new file mode 100644 index 00000000..ae761355 --- /dev/null +++ b/TopModel.Generator.Jpa/JpaConverterGenerator.cs @@ -0,0 +1,72 @@ +using Microsoft.Extensions.Logging; +using TopModel.Core; +using TopModel.Generator.Core; + +namespace TopModel.Generator.Jpa; + +/// +/// Générateur de DAOs JPA. +/// +public class JpaConverterGenerator : ClassGeneratorBase +{ + private readonly ILogger _logger; + + public JpaConverterGenerator(ILogger 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 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();"); + 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, $"}}"); + } +} \ No newline at end of file diff --git a/TopModel.Generator.Jpa/JpaDaoGenerator.cs b/TopModel.Generator.Jpa/JpaDaoGenerator.cs index c5535ff1..b33c5432 100644 --- a/TopModel.Generator.Jpa/JpaDaoGenerator.cs +++ b/TopModel.Generator.Jpa/JpaDaoGenerator.cs @@ -21,7 +21,7 @@ public JpaDaoGenerator(ILogger 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) diff --git a/TopModel.Generator.Jpa/JpaMapperGenerator.cs b/TopModel.Generator.Jpa/JpaMapperGenerator.cs index 93d6b189..d289d02e 100644 --- a/TopModel.Generator.Jpa/JpaMapperGenerator.cs +++ b/TopModel.Generator.Jpa/JpaMapperGenerator.cs @@ -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; } diff --git a/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs b/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs index 4a545d78..6d048418 100644 --- a/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs +++ b/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs @@ -22,7 +22,7 @@ public void WriteEnumConstructor(JavaWriter fw, Class classe, List 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();"); @@ -35,7 +35,7 @@ public void WriteEnumConstructor(JavaWriter fw, Class classe, List 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"; @@ -61,13 +61,13 @@ public void WriteEnumConstructor(JavaWriter fw, Class classe, List 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, $"}}"); diff --git a/TopModel.Generator.Jpa/JpaModelGenerator.cs b/TopModel.Generator.Jpa/JpaModelGenerator.cs index be5006d1..085b1478 100644 --- a/TopModel.Generator.Jpa/JpaModelGenerator.cs +++ b/TopModel.Generator.Jpa/JpaModelGenerator.cs @@ -80,15 +80,16 @@ 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;"); @@ -96,19 +97,32 @@ protected override void HandleClass(string fileName, Class classe, string tag) 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 ? ";" : ",")}"); + } } } @@ -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); } @@ -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); @@ -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) { @@ -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) @@ -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}'"); diff --git a/TopModel.Generator.Jpa/JpaModelPropertyGenerator.cs b/TopModel.Generator.Jpa/JpaModelPropertyGenerator.cs index bbfc4e24..cc28888d 100644 --- a/TopModel.Generator.Jpa/JpaModelPropertyGenerator.cs +++ b/TopModel.Generator.Jpa/JpaModelPropertyGenerator.cs @@ -154,7 +154,7 @@ public void WriteProperty(JavaWriter fw, Class classe, IProperty property, strin case CompositionProperty cp: WriteCompositionProperty(fw, cp, tag); break; - case AssociationProperty { Association.IsPersistent: true } ap: + case AssociationProperty { Association.IsPersistent: true } ap when !(_config.EnumsAsEnum && _config.CanClassUseEnums(ap.Association, _classes)): WriteAssociationProperty(fw, classe, ap, tag); break; case AliasProperty alp: @@ -212,7 +212,7 @@ private string GetterToCompareCompositePkPk(IProperty pk) private bool ShouldWriteColumnAnnotation(Class classe, IProperty property) { - return (classe.IsPersistent || _config.UseJdbc) && (property.Domain is null || !_config.GetImplementation(property.Domain)!.Annotations + return !(_config.EnumsAsEnum && _config.CanClassUseEnums(classe, _classes)) && (classe.IsPersistent || _config.UseJdbc) && (property.Domain is null || !_config.GetImplementation(property.Domain)!.Annotations .Where(i => classe.IsPersistent && (Target.Persisted & i.Target) > 0 || !classe.IsPersistent && (Target.Dto & i.Target) > 0) @@ -228,9 +228,9 @@ private void WriteAliasProperty(JavaWriter fw, Class classe, AliasProperty prope fw.WriteDocEnd(1); var javaOrJakarta = _config.PersistenceMode.ToString().ToLower(); - var shouldWriteAssociation = classe.IsPersistent && property.Property is AssociationProperty; + var shouldWriteAssociation = classe.IsPersistent && property.Property is AssociationProperty ap && !(_config.EnumsAsEnum && _config.CanClassUseEnums(ap.Class, _classes)); - if (property.PrimaryKey && classe.IsPersistent) + if (ShouldWriteIdAnnotation(classe, property)) { WriteIdAnnotation(fw, classe, property); } @@ -259,7 +259,7 @@ private void WriteAliasProperty(JavaWriter fw, Class classe, AliasProperty prope WriteValidationAnnotations(fw, javaOrJakarta); } - if (_config.CanClassUseEnums(property.Property.Class) && property.Property.PrimaryKey && classe.IsPersistent && !_config.UseJdbc) + if (_config.CanClassUseEnums(property.Property.Class) && !_config.EnumsAsEnum && property.Property.PrimaryKey && classe.IsPersistent && !_config.UseJdbc) { WriteEnumAnnotation(fw, javaOrJakarta); } @@ -271,7 +271,7 @@ private void WriteAliasProperty(JavaWriter fw, Class classe, AliasProperty prope var defaultValue = _config.GetValue(property, _classes); var suffix = defaultValue != "null" ? $" = {defaultValue}" : string.Empty; - var isAssociationNotPersistent = property.Property is AssociationProperty ap && !ap.Association.IsPersistent; + var isAssociationNotPersistent = property.Property is AssociationProperty asp && !asp.Association.IsPersistent; var useClassForAssociation = classe.IsPersistent && !isAssociationNotPersistent && !_config.UseJdbc; fw.WriteLine(1, $"private {_config.GetType(property, useClassForAssociation: useClassForAssociation)} {(isAssociationNotPersistent && !shouldWriteAssociation ? property.NameCamel : property.NameByClassCamel)}{suffix};"); } @@ -304,7 +304,7 @@ private void WriteAssociationProperty(JavaWriter fw, Class classe, AssociationPr fw.AddImport($"{javaOrJakarta}.persistence.FetchType"); fw.AddImport($"{javaOrJakarta}.persistence.{property.Type}"); - if (!property.PrimaryKey || classe.PrimaryKey.Count() <= 1) + if ((!property.PrimaryKey || classe.PrimaryKey.Count() <= 1) && !(_config.EnumsAsEnum && _config.CanClassUseEnums(property.Class, _classes))) { WriteAssociationAnnotations(fw, classe, property, 1); } @@ -329,7 +329,7 @@ private void WriteAssociationProperty(JavaWriter fw, Class classe, AssociationPr } } - if (property.PrimaryKey) + if (property.PrimaryKey && !(_config.EnumsAsEnum && _config.CanClassUseEnums(property.Class, _classes))) { fw.AddImport($"{javaOrJakarta}.persistence.Id"); fw.WriteLine(1, "@Id"); @@ -446,7 +446,7 @@ private void WriteIFieldProperty(JavaWriter fw, Class classe, IProperty property var javaOrJakarta = _config.PersistenceMode.ToString().ToLower(); fw.WriteDocEnd(1); - if (property.PrimaryKey && classe.IsPersistent) + if (ShouldWriteIdAnnotation(classe, property)) { WriteIdAnnotation(fw, classe, property); } @@ -456,12 +456,17 @@ private void WriteIFieldProperty(JavaWriter fw, Class classe, IProperty property WriteColumnAnnotation(fw, property, 1); } + if (property is AssociationProperty ap && _config.EnumsAsEnum && _config.CanClassUseEnums(ap.Association, _classes)) + { + WriteConvertEnumAnnotation(fw, ap, tag); + } + if (property.Required && !property.PrimaryKey && (!classe.IsPersistent || _config.UseJdbc)) { WriteValidationAnnotations(fw, javaOrJakarta); } - if (_config.CanClassUseEnums(classe) && property.PrimaryKey && !_config.UseJdbc) + if (_config.CanClassUseEnums(classe) && property.PrimaryKey && !_config.UseJdbc && !_config.EnumsAsEnum) { WriteEnumAnnotation(fw, javaOrJakarta); } @@ -473,11 +478,28 @@ private void WriteIFieldProperty(JavaWriter fw, Class classe, IProperty property var defaultValue = _config.GetValue(property, _classes); var suffix = defaultValue != "null" ? $" = {defaultValue}" : string.Empty; - var isAssociationNotPersistent = property is AssociationProperty ap && !ap.Association.IsPersistent; + var isAssociationNotPersistent = property is AssociationProperty asp && !asp.Association.IsPersistent; var useClassForAssociation = classe.IsPersistent && !isAssociationNotPersistent && !_config.UseJdbc; fw.WriteLine(1, $"private {_config.GetType(property, useClassForAssociation: useClassForAssociation)} {(isAssociationNotPersistent ? property.NameCamel : property.NameByClassCamel)}{suffix};"); } + private void WriteConvertEnumAnnotation(JavaWriter fw, AssociationProperty property, string tag) + { + var javaOrJakarta = _config.PersistenceMode.ToString().ToLower(); + fw.AddImport($"{javaOrJakarta}.persistence.Convert"); + var packageName = _config.ResolveVariables( + _config.EnumConverterPath!, + tag, + module: property.Association.Namespace.Module).ToPackageName(); + fw.AddImport($"{packageName}.{_config.GetType(property, useClassForAssociation: true)}Converter"); + fw.WriteLine(1, $"@Convert(converter = {_config.GetType(property, useClassForAssociation: true)}Converter.class)"); + } + + private bool ShouldWriteIdAnnotation(Class classe, IProperty property) + { + return property.PrimaryKey && classe.IsPersistent && !(_config.EnumsAsEnum && _config.CanClassUseEnums(property.Class, _classes)); + } + private void WriteIdAnnotation(JavaWriter fw, Class classe, IProperty property) { var javaOrJakarta = _config.PersistenceMode.ToString().ToLower(); diff --git a/TopModel.Generator.Jpa/jpa.config.json b/TopModel.Generator.Jpa/jpa.config.json index 03a63598..7d87f074 100644 --- a/TopModel.Generator.Jpa/jpa.config.json +++ b/TopModel.Generator.Jpa/jpa.config.json @@ -91,6 +91,11 @@ "description": "Localisation des enums du modèle, relative au répertoire de génération.", "default": "javagen:{app}/enums/{module}" }, + "enumConverterPath": { + "type": "string", + "description": "Localisation des converters des enums du modèle, relative au répertoire de génération.", + "default": "javagen:{app}/converters/{module}" + }, "apiPath": { "type": "string", "description": "Localisation du l'API générée (client ou serveur), relative au répertoire de génération. Par défaut, 'javagen:{app}/api/{module}'.", @@ -185,6 +190,11 @@ "description": "Option pour générer des getters et setters vers l'enum des références plutôt que sur la table", "default": "false" }, + "enumsAsEnum": { + "type": "boolean", + "description": "Option pour remplacer les classes de listes de références par des enums", + "default": "false" + }, "associationAdders": { "type": "boolean", "description": "Option pour générer des méthodes d'ajouts pour les associations oneToMany et manyToMany. Ces méthodes permettent de synchroniser les objets ajoutés", diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/DroitConverter.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/DroitConverter.java new file mode 100644 index 00000000..491f82c0 --- /dev/null +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/DroitConverter.java @@ -0,0 +1,22 @@ +//// +//// ATTENTION CE FICHIER EST GENERE AUTOMATIQUEMENT ! +//// + +package topmodel.jpa.sample.demo.converters.securite.profil; + +import jakarta.persistence.AttributeConverter; + +import topmodel.jpa.sample.demo.entities.securite.profil.Droit; + +public class DroitConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(Droit item) { + return item == null ? null : item.getCode().name(); + } + + @Override + public Droit convertToEntityAttribute(String code) { + return Droit.from(code); + } +} diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/TypeDroitConverter.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/TypeDroitConverter.java new file mode 100644 index 00000000..c66c42bf --- /dev/null +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/TypeDroitConverter.java @@ -0,0 +1,22 @@ +//// +//// ATTENTION CE FICHIER EST GENERE AUTOMATIQUEMENT ! +//// + +package topmodel.jpa.sample.demo.converters.securite.profil; + +import jakarta.persistence.AttributeConverter; + +import topmodel.jpa.sample.demo.entities.securite.profil.TypeDroit; + +public class TypeDroitConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(TypeDroit item) { + return item == null ? null : item.getCode().name(); + } + + @Override + public TypeDroit convertToEntityAttribute(String code) { + return TypeDroit.from(code); + } +} diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/utilisateur/TypeUtilisateurConverter.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/utilisateur/TypeUtilisateurConverter.java new file mode 100644 index 00000000..faca0733 --- /dev/null +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/utilisateur/TypeUtilisateurConverter.java @@ -0,0 +1,22 @@ +//// +//// ATTENTION CE FICHIER EST GENERE AUTOMATIQUEMENT ! +//// + +package topmodel.jpa.sample.demo.converters.securite.utilisateur; + +import jakarta.persistence.AttributeConverter; + +import topmodel.jpa.sample.demo.entities.securite.utilisateur.TypeUtilisateur; + +public class TypeUtilisateurConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(TypeUtilisateur item) { + return item == null ? null : item.getCode().name(); + } + + @Override + public TypeUtilisateur convertToEntityAttribute(String code) { + return TypeUtilisateur.from(code); + } +} diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Droit.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Droit.java index a2f2ce67..36d84a96 100644 --- a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Droit.java +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Droit.java @@ -4,94 +4,82 @@ package topmodel.jpa.sample.demo.entities.securite.profil; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Immutable; +import java.util.NoSuchElementException; import jakarta.annotation.Generated; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Enumerated; -import jakarta.persistence.EnumType; -import jakarta.persistence.FetchType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; -import jakarta.persistence.Transient; +import jakarta.persistence.Convert; +import topmodel.jpa.sample.demo.converters.securite.profil.TypeDroitConverter; import topmodel.jpa.sample.demo.enums.securite.profil.DroitCode; /** * Droits de l'application. */ @Generated("TopModel : https://github.com/klee-contrib/topmodel") -@Entity -@Table(name = "DROIT") -@Immutable -@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) -public class Droit { - - @Transient - public static final Droit CREATE = new Droit(DroitCode.CREATE); - @Transient - public static final Droit DELETE = new Droit(DroitCode.DELETE); - @Transient - public static final Droit READ = new Droit(DroitCode.READ); - @Transient - public static final Droit UPDATE = new Droit(DroitCode.UPDATE); +public enum Droit { + Create(DroitCode.CREATE), + Delete(DroitCode.DELETE), + Read(DroitCode.READ), + Update(DroitCode.UPDATE); /** * Code du droit. */ - @Id - @Column(name = "DRO_CODE", nullable = false, length = 10, columnDefinition = "varchar") - @Enumerated(EnumType.STRING) private DroitCode code; /** * Libellé du droit. */ - @Column(name = "DRO_LIBELLE", nullable = false, length = 100, columnDefinition = "varchar") private String libelle; /** * Type de profil pouvant faire l'action. */ - @ManyToOne(fetch = FetchType.LAZY, optional = false, targetEntity = TypeDroit.class) - @JoinColumn(name = "TDR_CODE", referencedColumnName = "TDR_CODE") + @Convert(converter = TypeDroitConverter.class) private TypeDroit typeDroit; - /** - * No arg constructor. - */ - public Droit() { - // No arg constructor - } - /** * Enum constructor. * @param code Code dont on veut obtenir l'instance. */ - public Droit(DroitCode code) { + private Droit(DroitCode code) { this.code = code; switch(code) { - case CREATE : - this.libelle = "securite.profil.droit.values.Create"; - this.typeDroit = TypeDroit.WRITE; - break; - case DELETE : - this.libelle = "securite.profil.droit.values.Delete"; - this.typeDroit = TypeDroit.ADMIN; - break; - case READ : - this.libelle = "securite.profil.droit.values.Read"; - this.typeDroit = TypeDroit.READ; - break; - case UPDATE : - this.libelle = "securite.profil.droit.values.Update"; - this.typeDroit = TypeDroit.WRITE; - break; + case CREATE : + this.libelle = "securite.profil.droit.values.Create"; + this.typeDroit = TypeDroit.WRITE; + break; + case DELETE : + this.libelle = "securite.profil.droit.values.Delete"; + this.typeDroit = TypeDroit.ADMIN; + break; + case READ : + this.libelle = "securite.profil.droit.values.Read"; + this.typeDroit = TypeDroit.READ; + break; + case UPDATE : + this.libelle = "securite.profil.droit.values.Update"; + this.typeDroit = TypeDroit.WRITE; + break; + } + } + + public static Droit from(String code) { + return from(DroitCode.valueOf(code)); + } + + public static Droit from(DroitCode code) { + switch(code) { + case CREATE: + return Create; + case DELETE: + return Delete; + case READ: + return Read; + case UPDATE: + return Update; + default: + throw new NoSuchElementException(code + " value unrecognized"); } } diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Profil.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Profil.java index b57b1972..895a29b9 100644 --- a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Profil.java +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/Profil.java @@ -15,19 +15,17 @@ import jakarta.annotation.Generated; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; +import jakarta.persistence.Convert; import jakarta.persistence.Entity; import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.JoinTable; -import jakarta.persistence.ManyToMany; import jakarta.persistence.OneToMany; -import jakarta.persistence.OrderBy; import jakarta.persistence.Table; +import topmodel.jpa.sample.demo.converters.securite.profil.ListConverter; import topmodel.jpa.sample.demo.entities.securite.utilisateur.Utilisateur; /** @@ -56,9 +54,8 @@ public class Profil { /** * Liste des droits du profil. */ - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "PROFIL_DROIT", joinColumns = @JoinColumn(name = "PRO_ID"), inverseJoinColumns = @JoinColumn(name = "DRO_CODE")) - @OrderBy("code ASC") + @Column(name = "DRO_CODE", precision = 10, columnDefinition = "varchar") + @Convert(converter = ListConverter.class) private List droits; /** diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/TypeDroit.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/TypeDroit.java index 5f11c138..4621b970 100644 --- a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/TypeDroit.java +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/profil/TypeDroit.java @@ -4,18 +4,9 @@ package topmodel.jpa.sample.demo.entities.securite.profil; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Immutable; +import java.util.NoSuchElementException; import jakarta.annotation.Generated; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Enumerated; -import jakarta.persistence.EnumType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import jakarta.persistence.Transient; import topmodel.jpa.sample.demo.enums.securite.profil.TypeDroitCode; @@ -23,56 +14,54 @@ * Type de droit. */ @Generated("TopModel : https://github.com/klee-contrib/topmodel") -@Entity -@Table(name = "TYPE_DROIT") -@Immutable -@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) -public class TypeDroit { - - @Transient - public static final TypeDroit ADMIN = new TypeDroit(TypeDroitCode.ADMIN); - @Transient - public static final TypeDroit READ = new TypeDroit(TypeDroitCode.READ); - @Transient - public static final TypeDroit WRITE = new TypeDroit(TypeDroitCode.WRITE); +public enum TypeDroit { + Admin(TypeDroitCode.ADMIN), + Read(TypeDroitCode.READ), + Write(TypeDroitCode.WRITE); /** * Code du type de droit. */ - @Id - @Column(name = "TDR_CODE", nullable = false, length = 10, columnDefinition = "varchar") - @Enumerated(EnumType.STRING) private TypeDroitCode code; /** * Libellé du type de droit. */ - @Column(name = "TDR_LIBELLE", nullable = false, length = 100, columnDefinition = "varchar") private String libelle; - /** - * No arg constructor. - */ - public TypeDroit() { - // No arg constructor - } - /** * Enum constructor. * @param code Code dont on veut obtenir l'instance. */ - public TypeDroit(TypeDroitCode code) { + private TypeDroit(TypeDroitCode code) { this.code = code; switch(code) { - case ADMIN : - this.libelle = "securite.profil.typeDroit.values.Admin"; - break; - case READ : - this.libelle = "securite.profil.typeDroit.values.Read"; - break; - case WRITE : - this.libelle = "securite.profil.typeDroit.values.Write"; - break; + case ADMIN : + this.libelle = "securite.profil.typeDroit.values.Admin"; + break; + case READ : + this.libelle = "securite.profil.typeDroit.values.Read"; + break; + case WRITE : + this.libelle = "securite.profil.typeDroit.values.Write"; + break; + } + } + + public static TypeDroit from(String code) { + return from(TypeDroitCode.valueOf(code)); + } + + public static TypeDroit from(TypeDroitCode code) { + switch(code) { + case ADMIN: + return Admin; + case READ: + return Read; + case WRITE: + return Write; + default: + throw new NoSuchElementException(code + " value unrecognized"); } } diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/SecuriteUtilisateurMappers.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/SecuriteUtilisateurMappers.java index 85b5b2b6..886e9e17 100644 --- a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/SecuriteUtilisateurMappers.java +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/SecuriteUtilisateurMappers.java @@ -75,7 +75,7 @@ public static Utilisateur toUtilisateur(UtilisateurWrite source, Utilisateur tar target.setAdresse(source.getAdresse()); target.setActif(source.getActif()); if (source.getTypeUtilisateurCode() != null) { - target.setTypeUtilisateur(new TypeUtilisateur(source.getTypeUtilisateurCode())); + target.setTypeUtilisateur(TypeUtilisateur.from(source.getTypeUtilisateurCode())); } return target; diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/TypeUtilisateur.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/TypeUtilisateur.java index 945d5045..02c3ec9c 100644 --- a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/TypeUtilisateur.java +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/TypeUtilisateur.java @@ -4,18 +4,9 @@ package topmodel.jpa.sample.demo.entities.securite.utilisateur; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Immutable; +import java.util.NoSuchElementException; import jakarta.annotation.Generated; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Enumerated; -import jakarta.persistence.EnumType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import jakarta.persistence.Transient; import topmodel.jpa.sample.demo.enums.securite.utilisateur.TypeUtilisateurCode; @@ -23,56 +14,54 @@ * Type d'utilisateur. */ @Generated("TopModel : https://github.com/klee-contrib/topmodel") -@Entity -@Table(name = "TYPE_UTILISATEUR") -@Immutable -@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) -public class TypeUtilisateur { - - @Transient - public static final TypeUtilisateur ADMIN = new TypeUtilisateur(TypeUtilisateurCode.ADMIN); - @Transient - public static final TypeUtilisateur CLIENT = new TypeUtilisateur(TypeUtilisateurCode.CLIENT); - @Transient - public static final TypeUtilisateur GEST = new TypeUtilisateur(TypeUtilisateurCode.GEST); +public enum TypeUtilisateur { + Admin(TypeUtilisateurCode.ADMIN), + Client(TypeUtilisateurCode.CLIENT), + Gestionnaire(TypeUtilisateurCode.GEST); /** * Code du type d'utilisateur. */ - @Id - @Column(name = "TUT_CODE", nullable = false, length = 10, columnDefinition = "varchar") - @Enumerated(EnumType.STRING) private TypeUtilisateurCode code; /** * Libellé du type d'utilisateur. */ - @Column(name = "TUT_LIBELLE", nullable = false, length = 100, columnDefinition = "varchar") private String libelle; - /** - * No arg constructor. - */ - public TypeUtilisateur() { - // No arg constructor - } - /** * Enum constructor. * @param code Code dont on veut obtenir l'instance. */ - public TypeUtilisateur(TypeUtilisateurCode code) { + private TypeUtilisateur(TypeUtilisateurCode code) { this.code = code; switch(code) { - case ADMIN : - this.libelle = "securite.utilisateur.typeUtilisateur.values.Admin"; - break; - case CLIENT : - this.libelle = "securite.utilisateur.typeUtilisateur.values.Client"; - break; - case GEST : - this.libelle = "securite.utilisateur.typeUtilisateur.values.Gestionnaire"; - break; + case ADMIN : + this.libelle = "securite.utilisateur.typeUtilisateur.values.Admin"; + break; + case CLIENT : + this.libelle = "securite.utilisateur.typeUtilisateur.values.Client"; + break; + case GEST : + this.libelle = "securite.utilisateur.typeUtilisateur.values.Gestionnaire"; + break; + } + } + + public static TypeUtilisateur from(String code) { + return from(TypeUtilisateurCode.valueOf(code)); + } + + public static TypeUtilisateur from(TypeUtilisateurCode code) { + switch(code) { + case ADMIN: + return Admin; + case CLIENT: + return Client; + case GEST: + return Gestionnaire; + default: + throw new NoSuchElementException(code + " value unrecognized"); } } diff --git a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/Utilisateur.java b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/Utilisateur.java index 0c268563..6ab84459 100644 --- a/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/Utilisateur.java +++ b/samples/generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/entities/securite/utilisateur/Utilisateur.java @@ -13,6 +13,7 @@ import jakarta.annotation.Generated; import jakarta.persistence.Column; +import jakarta.persistence.Convert; import jakarta.persistence.Entity; import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; @@ -24,8 +25,8 @@ import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; +import topmodel.jpa.sample.demo.converters.securite.utilisateur.TypeUtilisateurConverter; import topmodel.jpa.sample.demo.entities.securite.profil.Profil; -import topmodel.jpa.sample.demo.enums.securite.utilisateur.TypeUtilisateurCode; /** * Utilisateur de l'application. @@ -91,9 +92,9 @@ public class Utilisateur { /** * Type d'utilisateur. */ - @ManyToOne(fetch = FetchType.LAZY, optional = false, targetEntity = TypeUtilisateur.class) - @JoinColumn(name = "TUT_CODE", referencedColumnName = "TUT_CODE") - private TypeUtilisateur typeUtilisateur = new TypeUtilisateur(TypeUtilisateurCode.GEST); + @Column(name = "TUT_CODE", nullable = false, length = 10, columnDefinition = "varchar") + @Convert(converter = TypeUtilisateurConverter.class) + private TypeUtilisateur typeUtilisateur = TypeUtilisateurCode.GEST; /** * Date de création de l'utilisateur. diff --git a/samples/generators/jpa/topmodel.config b/samples/generators/jpa/topmodel.config index 6a02b809..2368873d 100644 --- a/samples/generators/jpa/topmodel.config +++ b/samples/generators/jpa/topmodel.config @@ -28,4 +28,5 @@ jpa: persistenceMode: jakarta daosInterface: topmodel.jpa.sample.demo.daos.repository.CustomCrudRepository daosAbstract: true - mappersInClass: true \ No newline at end of file + mappersInClass: true + enumsAsEnum: true \ No newline at end of file diff --git a/samples/model/jpa.topmodel.lock b/samples/model/jpa.topmodel.lock index d307af2e..82cb10e6 100644 --- a/samples/model/jpa.topmodel.lock +++ b/samples/model/jpa.topmodel.lock @@ -2,14 +2,17 @@ # ATTENTION CE FICHIER EST GENERE AUTOMATIQUEMENT ! # -version: 2.1.2 +version: 2.1.3 custom: - ../../../TopModel.Generator.Jpa: b7b41bad6aa1f4963dda4549de26efcd + ../../../TopModel.Generator.Jpa: ce3b99073a3e0586992244c25da38664 generatedFiles: - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/api/client/securite/profil/ProfilClient.java - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/api/client/securite/utilisateur/UtilisateurClient.java - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/api/server/securite/profil/ProfilController.java - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/api/server/securite/utilisateur/UtilisateurController.java + - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/DroitConverter.java + - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/profil/TypeDroitConverter.java + - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/converters/securite/utilisateur/TypeUtilisateurConverter.java - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/daos/securite/profil/AbstractProfilDAO.java - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/daos/securite/utilisateur/AbstractUtilisateurDAO.java - ../generators/jpa/src/main/javagen/topmodel/jpa/sample/demo/dtos/securite/profil/ProfilItem.java