diff --git a/generators/bootstrap-application/generator.spec.mjs b/generators/bootstrap-application/generator.spec.mjs index 91d3b48bbd05..c13c0cccacd4 100644 --- a/generators/bootstrap-application/generator.spec.mjs +++ b/generators/bootstrap-application/generator.spec.mjs @@ -58,10 +58,7 @@ const filterEntity = entity => ({ ownFields: '[ownFields] getter', fields: '[fields] getter', derivedFields: '[derivedFields] getter', - ids: entity.primaryKey.ids.map(id => ({ - ...id, - field: `[field] ${id.field.fieldName}`, - })), + ids: '[ids] getter', }, }); @@ -207,6 +204,8 @@ Object { "fieldName": "id", "fieldNameAsDatabaseColumn": "id", "fieldNameCapitalized": "Id", + "fieldNameDotted": "id", + "fieldNameDottedAsserted": "id!", "fieldNameHumanized": "ID", "fieldNameUnderscored": "id", "fieldTranslationKey": "global.field.id", @@ -517,19 +516,7 @@ Object { "fields": "[fields] getter", "hasLong": true, "hasUUID": false, - "ids": Array [ - Object { - "autoGenerate": true, - "field": "[field] id", - "getter": "getId", - "name": "id", - "nameCapitalized": "Id", - "nameDotted": "id", - "nameDottedAsserted": "id!", - "relationshipsPath": Array [], - "setter": "setId", - }, - ], + "ids": "[ids] getter", "name": "id", "nameCapitalized": "Id", "ownFields": "[ownFields] getter", @@ -631,6 +618,8 @@ Object { "fieldName": "id", "fieldNameAsDatabaseColumn": "id", "fieldNameCapitalized": "Id", + "fieldNameDotted": "id", + "fieldNameDottedAsserted": "id!", "fieldNameHumanized": "Id", "fieldNameUnderscored": "id", "fieldTranslationKey": "jhipsterApp.entityA.id", @@ -739,19 +728,7 @@ Object { "fields": "[fields] getter", "hasLong": false, "hasUUID": true, - "ids": Array [ - Object { - "autoGenerate": true, - "field": "[field] id", - "getter": "getId", - "name": "id", - "nameCapitalized": "Id", - "nameDotted": "id", - "nameDottedAsserted": "id!", - "relationshipsPath": Array [], - "setter": "setId", - }, - ], + "ids": "[ids] getter", "name": "id", "nameCapitalized": "Id", "ownFields": "[ownFields] getter", @@ -909,6 +886,8 @@ Object { "fieldName": "id", "fieldNameAsDatabaseColumn": "id", "fieldNameCapitalized": "Id", + "fieldNameDotted": "id", + "fieldNameDottedAsserted": "id!", "fieldNameHumanized": "Id", "fieldNameUnderscored": "id", "fieldTranslationKey": "jhipsterApp.entityA.id", @@ -1017,19 +996,7 @@ Object { "fields": "[fields] getter", "hasLong": false, "hasUUID": true, - "ids": Array [ - Object { - "autoGenerate": true, - "field": "[field] id", - "getter": "getId", - "name": "id", - "nameCapitalized": "Id", - "nameDotted": "id", - "nameDottedAsserted": "id!", - "relationshipsPath": Array [], - "setter": "setId", - }, - ], + "ids": "[ids] getter", "name": "id", "nameCapitalized": "Id", "ownFields": "[ownFields] getter", diff --git a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs index 429d9c675c75..6c7aea2a252d 100644 --- a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs +++ b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs @@ -47,12 +47,12 @@ <%_ } _%> <%_ for (relationship of relationships) { if ((relationship.relationshipType === 'many-to-one' || (relationship.relationshipType === 'one-to-one' && relationship.ownerSide === true)) - && !relationship.id) { + && (!relationship.id || entity.primaryKey.composite)) { relationship.otherEntity.primaryKey.fields.forEach(idField => { - const uniqueConstraintName = relationship.relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationship.columnName + '_' + idField.columnName, entity.prodDatabaseType) : null; + const uniqueConstraintName = relationship.relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationship.columnNamePrefix + idField.columnName, entity.prodDatabaseType) : null; _%> - - unique="true" uniqueConstraintName="<%= uniqueConstraintName %>"<% } %> /> + + primaryKey="true" <% } %>nullable="<%= relationship.nullable %>"<% if (uniqueConstraintName) { %> unique="true" uniqueConstraintName="<%= uniqueConstraintName %>"<% } %> /> <%_ }); } @@ -74,7 +74,7 @@ _%> <%_ for (field of relationship.otherEntity.primaryKey.fields) { _%> - + <%_ } _%> @@ -85,7 +85,7 @@ _%> <%_ } _%> - + <%_ } _%> <%_ } _%> @@ -113,17 +113,12 @@ _%> <%_ } _%> <%_ } _%> - <%_ for (relationship of relationships) { - if (relationship.relationshipValidate === true && relationship.relationshipRequired - && (relationship.relationshipType === "many-to-one" - || (relationship.relationshipType === "one-to-one" && relationship.ownerSide === true - && (relationship.id == null || relationship.id === false)) - )) { - _%> - <%_ for (field of relationship.otherEntity.primaryKey.fields) { _%> - - <%_ } _%> - <%_ } _%> + <%_ const relationshipsToGenerate = [...relationships.filter(r => r.id && entity.primaryKey.composite), ...relationships.filter(r => !r.id && r.relationshipRequired && (r.relationshipManyToOne || (r.relationshipOneToOne && r.ownerSide)))]; + for (relationship of relationshipsToGenerate) { + _%> + <%_ for (field of relationship.otherEntity.primaryKey.fields) { _%> + + <%_ } _%> <%_ } _%> diff --git a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/fake-data/table_entity.csv.ejs b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/fake-data/table_entity.csv.ejs index 84cd915a8abe..6eb95021ee45 100644 --- a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/fake-data/table_entity.csv.ejs +++ b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/fake-data/table_entity.csv.ejs @@ -28,16 +28,9 @@ for (field of fieldsToGenerate) { header.push(field.columnName + '_content_type'); } } -for (relationship of relationships) { - const { relationshipType, joinColumnNames } = relationship; - if ( - (relationshipType === "many-to-one" - || (relationshipType === "one-to-one" && relationship.ownerSide === true - && (relationship.id == null || relationship.id === false)) - ) && (relationship.relationshipValidate === true && relationship.relationshipRequired) - ) { - header.push(joinColumnNames[0]); - } +const relationshipsToGenerate = [...relationships.filter(r => r.id && entity.primaryKey.composite), ...relationships.filter(r => !r.id && r.relationshipRequired && (r.relationshipManyToOne || (r.relationshipOneToOne && r.ownerSide)))]; +for (relationship of relationshipsToGenerate) { + header.push(...relationship.joinColumnNames); } table.push(header); @@ -59,27 +52,21 @@ for (lineNb = 0; lineNb < entity.fakeDataCount; lineNb++) { } line.push(data); - if (field.columnType === 'blob' || field.columnType === 'longblob') { + if (field.fieldType === 'byte[]' && field.fieldTypeBlobContent !== 'text') { line.push('image/png'); } } - for (relationship of relationships) { - const relationshipType = relationship.relationshipType; - if ( - (relationshipType === "many-to-one" - || (relationshipType === "one-to-one" && relationship.ownerSide === true - && (relationship.id == null || relationship.id === false)) - ) && (relationship.relationshipValidate === true && relationship.relationshipRequired) - ) { - const otherLiquibaseFakeData = relationship.otherEntity.liquibaseFakeData; - let relationshipRow = lineNb; - if (relationshipRow >= relationship.otherEntity.fakeDataCount && !relationship.unique) { - relationshipRow = entity.faker.datatype.number({min: 1, max: relationship.otherEntity.fakeDataCount}) - 1; - } - if (relationshipRow < relationship.otherEntity.fakeDataCount) { - line.push(otherLiquibaseFakeData[relationshipRow][relationship.otherEntity.primaryKey.name]); - } + for (relationship of relationshipsToGenerate) { + let relationshipRow = lineNb; + if (relationshipRow >= relationship.otherEntity.fakeDataCount && !relationship.unique) { + relationshipRow = entity.faker.datatype.number({min: 1, max: relationship.otherEntity.fakeDataCount}) - 1; + } + if (relationshipRow < relationship.otherEntity.fakeDataCount) { + relationship.otherEntity.primaryKey.fields.forEach(field => { + const otherLiquibaseFakeData = field.entity.liquibaseFakeData; + line.push(otherLiquibaseFakeData[relationshipRow][field.propertyName]); + }) } } if (line.length === header.length) { diff --git a/generators/entity-client/files-angular.cjs b/generators/entity-client/files-angular.cjs index 066213fdfed2..2c30f4b16a31 100644 --- a/generators/entity-client/files-angular.cjs +++ b/generators/entity-client/files-angular.cjs @@ -177,7 +177,7 @@ async function writeAngularFiles() { sections: angularFiles, rootTemplatesPath: 'angular', transform: !application.enableTranslation ? [replaceAngularTranslations] : undefined, - context: { ...application, ...entity }, + context: { ...application, ...entity, entity }, }); if (!entity.embedded) { diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.test-samples.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.test-samples.ts.ejs index 2ca8bf3fdab8..564ef45dc9b0 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.test-samples.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.test-samples.ts.ejs @@ -19,15 +19,12 @@ <%_ const enumImports = this.generateEntityClientEnumImports(fields, clientFramework); _%> -<%_ if (fieldsContainDate) { _%> -import dayjs from 'dayjs/esm'; -<%_ } _%> <%_ enumImports.forEach( (importedPath, importedType) => { _%> import { <%- importedType %> } from '<%- importedPath %>'; <%_ }); _%> -import { I<%= entityAngularName %><% if (primaryKey) { %>, New<%= entityAngularName %><% } %> } from './<%= entityFileName %>.model'; +import { I<%= entityAngularName %> } from './<%= entityFileName %>.model'; export const sampleWithRequiredData: I<%= entityAngularName %> = <%- this.generateTypescriptTestEntity(fields.filter(field => field.id || field.fieldValidationRequired).map(field => field.reference)) %>; diff --git a/generators/entity-server/files.js b/generators/entity-server/files.js index 5e45a386b534..4be596f28355 100644 --- a/generators/entity-server/files.js +++ b/generators/entity-server/files.js @@ -64,6 +64,16 @@ const modelFiles = { }, ], }, + { + condition: generator => generator.primaryKey && generator.primaryKey.composite && !generator.primaryKey.derived, + path: SERVER_MAIN_SRC_DIR, + templates: [ + { + file: 'package/domain/EntityId.java', + renameTo: generator => `${generator.entityAbsoluteFolder}/domain/${generator.persistClass}Id.java`, + }, + ], + }, ], modelTestFiles: [ { @@ -447,7 +457,8 @@ function writeFiles() { return this.writeFiles({ sections: serverFiles, rootTemplatesPath: application.reactive ? ['reactive', ''] : undefined, - context: { ...application, ...entity }, + // entity needed for recursive DTO + context: { ...application, ...entity, entity }, }); }, diff --git a/generators/entity-server/templates/partials/it_patch_update.partial.java.ejs b/generators/entity-server/templates/partials/it_patch_update.partial.java.ejs index bff932a3bc93..91a9d1f29cc0 100644 --- a/generators/entity-server/templates/partials/it_patch_update.partial.java.ejs +++ b/generators/entity-server/templates/partials/it_patch_update.partial.java.ejs @@ -21,6 +21,12 @@ int databaseSizeBeforeUpdate = <%= entityInstance %>Repository.findAll()<%= call // Update the <%= entityInstance %> using partial update <%= persistClass %> partialUpdated<%= persistClass %> = new <%= persistClass %>(); partialUpdated<%= persistClass %>.set<%= primaryKey.nameCapitalized %>(<%= persistInstance %>.get<%= primaryKey.nameCapitalized %>()); +<%_ primaryKey.composite && fields.filter(f => f.id).forEach(f => { _%> +partialUpdated<%= persistClass %>.set<%= f.fieldNameCapitalized %>(<%= persistInstance %>.get<%= f.fieldNameCapitalized %>()); +<%_ }) _%> +<%_ relationships.filter(r => r.id).forEach(r => { _%> +partialUpdated<%= persistClass %>.set<%= r.relationshipNameCapitalized %>(<%= persistInstance %>.get<%= r.relationshipNameCapitalized %>()); +<%_ }) _%> <%_ fieldsToUpdate = fields.filter(field => field.includeField) %> <%_ if (fluentMethods && fieldsToUpdate.length > 0) { _%> partialUpdated<%= persistClass %><% for (field of fieldsToUpdate) { %> @@ -47,7 +53,7 @@ webTestClient .expectStatus() .isOk(); <%_ } else { _%> -rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, partialUpdated<%= persistClass %>.get<%= primaryKey.nameCapitalized %>())<% if (testsNeedCsrf) { %>.with(csrf())<% }%> +rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, <%- persistInstanceUrlId.replaceAll(persistInstance, 'partialUpdated' + persistClass) %>)<% if (testsNeedCsrf) { %>.with(csrf())<% }%> .contentType("application/merge-patch+json") .content(TestUtil.convertObjectToJsonBytes(<%= 'partialUpdated' + persistClass %>))) .andExpect(status().isOk()); diff --git a/generators/entity-server/templates/partials/save_template.ejs b/generators/entity-server/templates/partials/save_template.ejs index 17deca4b6fb2..7e48158750d4 100644 --- a/generators/entity-server/templates/partials/save_template.ejs +++ b/generators/entity-server/templates/partials/save_template.ejs @@ -43,7 +43,7 @@ if (isUsingMapsId) { <%_ resultEntity = persistInstance; _%> <%= persistClass %> <%= persistInstance %> = <%= dtoToEntity %>(<%= instanceName %>); <%_ if (isUsingMapsId) { _%> - <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); + <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <% if (primaryKey.composite) { %><%= mapper %>.toEntity(<%= instanceName %>)<% } else { %><%= instanceName %><% } %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>(); <%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= persistInstance %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= mapsIdAssoc.relationshipName %><%_ } _%>); <%_ } _%> <%= persistInstance %> = <%= entityInstance %>Repository.save(<%= persistInstance %>); @@ -51,7 +51,7 @@ if (isUsingMapsId) { <%_ } else { resultEntity = 'result'; _%> <%_ if (isUsingMapsId) { _%> - <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); + <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>(); <%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= instanceName %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= otherEntityName %><%_ } _%>); <%_ } _%> <%= returnPrefix %> <%= entityInstance %>Repository.save(<%= persistInstance %>); diff --git a/generators/entity-server/templates/partials/update_template.ejs b/generators/entity-server/templates/partials/update_template.ejs index 30c51e52cfa9..783a13af8410 100644 --- a/generators/entity-server/templates/partials/update_template.ejs +++ b/generators/entity-server/templates/partials/update_template.ejs @@ -41,7 +41,7 @@ if (isUsingMapsId) { <%= persistInstance %>.setIsPersisted(); <%_ } _%> <%_ if (isUsingMapsId) { _%> - <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); + <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <% if (primaryKey.composite) { %><%= mapper %>.toEntity(<%= instanceName %>)<% } else { %><%= instanceName %><% } %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>(); <%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= persistInstance %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= mapsIdAssoc.relationshipName %><%_ } _%>); <%_ } _%> <%_ if (updatableEntity) { _%> @@ -53,7 +53,7 @@ if (isUsingMapsId) { <%_ } else { resultEntity = 'result'; _%> <%_ if (isUsingMapsId) { _%> - <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); + <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>(); <%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= instanceName %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= otherEntityName %><%_ } _%>); <%_ } _%> <%_ if (isPersisted) { _%> diff --git a/generators/entity-server/templates/src/main/java/package/common/field_validators.ejs b/generators/entity-server/templates/src/main/java/package/common/field_validators.ejs index 63b4cd19ba44..dcbed0e6a966 100644 --- a/generators/entity-server/templates/src/main/java/package/common/field_validators.ejs +++ b/generators/entity-server/templates/src/main/java/package/common/field_validators.ejs @@ -25,7 +25,7 @@ if (field.fieldValidate) { const MAX_VALUE = 2147483647; const isBlob = field.fieldTypeBytes; - if (field.fieldValidationRequired && !isBlob) { + if (field.fieldValidationRequired && !field.autoGenerate && !isBlob) { // reactive tests need a default validation message because lookup is blocking validators.push('@NotNull' + (reactive ? '(message = "must not be null")' : '')); } diff --git a/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs b/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs index 474c640b95b4..851209eeba6e 100644 --- a/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs +++ b/generators/entity-server/templates/src/main/java/package/common/inject_template.ejs @@ -21,6 +21,9 @@ if (viaService) { beans.push({class: `${entityClass}Service`, instance: `${entityInstance}Service`}); beans.push({class: `${entityClass}Repository`, instance: `${entityInstance}Repository`}); + if (dtoMapstruct && primaryKey.composite) { + beans.push({class: `${entityClass}Mapper`, instance: `${entityInstance}Mapper`}); + } if (queryService) { beans.push({class: `${entityClass}QueryService`, instance: `${entityInstance}QueryService`}); } @@ -32,7 +35,7 @@ } } else { beans.push({class: `${entityClass}Repository`, instance: `${entityInstance}Repository`}); - if (dtoMapstruct) { + if (dtoMapstruct || primaryKey.composite) { beans.push({class: `${entityClass}Mapper`, instance: `${entityInstance}Mapper`}); } if (searchEngineElasticsearch) { diff --git a/generators/entity-server/templates/src/main/java/package/common/patch_template.ejs b/generators/entity-server/templates/src/main/java/package/common/patch_template.ejs index 6bb7d69c072e..77c17834e472 100644 --- a/generators/entity-server/templates/src/main/java/package/common/patch_template.ejs +++ b/generators/entity-server/templates/src/main/java/package/common/patch_template.ejs @@ -31,7 +31,7 @@ _%> Optional<<%= instanceType %>> result = <%= entityInstance %>Service.partialUpdate(<%= instanceName %>); <%_ } _%> <%_ } else { %> -<%- returnPrefix %> <%= entityInstance %>Repository.findById(<%= instanceName %>.get<%= primaryKey.nameCapitalized %>()) +<%- returnPrefix %> <%= entityInstance %>Repository.findById(<%= primaryKey.composite && dtoMapstruct ? `${mapper}.toEntity(${instanceName})` : instanceName %>.get<%= primaryKey.nameCapitalized %>()) .map(existing<%= entityClass %> -> { <%_ if (dtoMapstruct) { _%> <%= mapper %>.partialUpdate(existing<%= entityClass %>, <%= instanceName %>); diff --git a/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.ejs b/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.ejs index f31de5283755..d23bb58242b6 100644 --- a/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.ejs +++ b/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.ejs @@ -102,13 +102,13 @@ public class <%= persistClass %> <&- fragments.extendsSection() -&>implements Se private static final long serialVersionUID = 1L; <%_ if (!embedded && primaryKey.composite) { _%> - @Id + @EmbeddedId private <%= primaryKey.type %> <%= primaryKey.name %>; <%_ } _%> <&- fragments.classStaticFieldsSection() -&> <&- fragments.classFieldsSection() -&> -<%_ for (const field of fields.filter(field => !field.javaInherited && !field.transient && (embedded || !field.id || !primaryKey.composite))) { _%> +<%_ for (const field of fields.filter(field => !field.javaInherited && !field.transient && (embedded || !(field.id && primaryKey.composite && primaryKey.fields.length === 1)))) { _%> <&- fragments.field<%- field.fieldNameCapitalized %>CustomDeclarationSection() -&> <&_ if (!fragments.field<%- field.fieldNameCapitalized %>CustomDeclarationSection()) { -&> <%_ if (typeof field.javadoc !== 'undefined') { _%> @@ -176,7 +176,24 @@ for (relationship of relationships.filter(relationship => !relationship.embedded <%_ }; _%> <&- fragments.classAdditionalRelationshipsSection() -&> // jhipster-needle-entity-add-field - JHipster will add fields here -<%_ for (const field of fields.filter(field => !field.transient && (embedded || !field.id || !primaryKey.composite))) { _%> +<%_ if (!embedded && primaryKey.composite) { _%> + + public <%= primaryKey.type %> get<%= primaryKey.nameCapitalized %>() { + return this.<%= primaryKey.name %>; + } + <%_ if (fluentMethods) { _%> + + public <%= persistClass %> <%= primaryKey.name %>(<%= primaryKey.type %> <%= primaryKey.name %>) { + this.set<%= primaryKey.nameCapitalized %>(<%= primaryKey.name %>); + return this; + } + <%_ } _%> + + public void set<%= primaryKey.nameCapitalized %>(<%= primaryKey.type %> <%= primaryKey.name %>) { + this.<%= primaryKey.name %> = <%= primaryKey.name %>; + } +<%_ } _%> +<%_ for (const field of fields.filter(field => !field.transient && (embedded || !(field.id && primaryKey.composite && primaryKey.fields.length === 1)))) { _%> <&- fragments.field<%- field.fieldNameCapitalized %>CustomMethodsSection() -&> <&_ if (!fragments.field<%- field.fieldNameCapitalized %>CustomMethodsSection()) { -&> diff --git a/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.javax_persistence.ejs b/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.javax_persistence.ejs index adda88d433ac..cc877aa9f6dc 100644 --- a/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.javax_persistence.ejs +++ b/generators/entity-server/templates/src/main/java/package/domain/Entity.java.jhi.javax_persistence.ejs @@ -35,14 +35,16 @@ import org.hibernate.annotations.Type; <%_ for (const field of fields) { -%> <&_ if (fragment.field<%- field.fieldNameCapitalized %>AnnotationSection) { -&> <%_ if (field.id) { _%> + <%_ if (primaryKey.fields.length === 1) { _%> @Id - <%_ if (field.jpaGeneratedValue === 'identity') { _%> + <%_ if (field.jpaGeneratedValue === 'identity') { _%> @GeneratedValue(strategy = GenerationType.IDENTITY) - <%_ } else if (field.jpaGeneratedValue === 'sequence') { _%> + <%_ } else if (field.jpaGeneratedValue === 'sequence') { _%> @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") @SequenceGenerator(name = "sequenceGenerator") - <%_ } else if (field.jpaGeneratedValue) { _%> + <%_ } else if (field.jpaGeneratedValue) { _%> @GeneratedValue + <%_ } _%> <%_ } _%> <%_ } _%> <%_ if (field.fieldIsEnum) { _%> @@ -62,7 +64,7 @@ import org.hibernate.annotations.Type; @Type(type = "uuid-char") @Column(name = "<%- field.fieldNameAsDatabaseColumn %>", length = 36<% if (field.fieldValidationRequired) { %>, nullable = false<% } %><% if (field.fieldValidationUnique) { %>, unique = true<% } %>) <%_ } else { _%> - @Column(name = "<%- field.fieldNameAsDatabaseColumn %>"<% if (field.fieldValidate === true) { %><% if (field.fieldValidationMaxLength) { %>, length = <%= field.fieldValidateRulesMaxlength %><% } %><% if (field.fieldValidationRequired) { %>, nullable = false<% } %><% if (field.fieldValidationUnique) { %>, unique = true<% } %><% } %>) + @Column(name = "<%- field.fieldNameAsDatabaseColumn %>"<% if (field.fieldValidate === true) { %><% if (field.fieldValidationMaxLength) { %>, length = <%= field.fieldValidateRulesMaxlength %><% } %><% if (field.fieldValidationRequired) { %>, nullable = false<% } %><% if (field.fieldValidationUnique) { %>, unique = true<% } %><% } %><%if (field.id && primaryKey.fields.length > 1) { %>, insertable = false, updatable = false<% } %>) <%_ } _%> <&_ } -&> <%_ } -%> @@ -85,6 +87,13 @@ import org.hibernate.annotations.Type; <%_ if (relationship.relationshipValidate) { _%> <%- include('relationship_validators', { relationship }); -%> <%_ } _%> + <%_ if (relationship.id && !reactive) { _%> + <%_ if (relationship.otherEntity.primaryKey.fields.length === 1) { _%> + @JoinColumn(insertable = false, updatable = false) + <%_ } else { _%> + @JoinColumns({<%- relationship.otherEntity.primaryKey.fields.map(field => '@JoinColumn(name = "' + relationship.columnNamePrefix + field.columnName + '", referencedColumnName = "' + field.columnName + '", insertable = false, updatable = false)').join(', ') %>}) + <%_ } _%> + <%_ } _%> <%_ } else if (relationship.relationshipManyToMany) { -%> @ManyToMany<% if (!relationship.ownerSide) { %>(mappedBy = "<%= relationship.otherEntityRelationshipNamePlural %>")<% } %> <%_ if (relationship.ownerSide) { _%> @@ -94,12 +103,12 @@ import org.hibernate.annotations.Type; @JoinTable(name = "<%= relationship.joinTable.name %>", joinColumns = <%= primaryKey.fields.length > 1 ? '{' : '' %> <%_ primaryKey.fields.forEach((field, idx) => { _%> - <%= idx === 0 ? '' : ',' %>@JoinColumn(name = "<%= `${entityTableName}_${field.columnName}` %>") + <%= idx === 0 ? '' : ',' %>@JoinColumn(name = "<%= `${entityTableName}_${field.columnName}` %>", referencedColumnName = "<%= field.columnName %>") <%_ }); _%> <%= primaryKey.fields.length > 1 ? '}' : '' %>, inverseJoinColumns = <%= relationship.otherEntity.primaryKey.fields.length > 1 ? '{' : '' %> <%_ relationship.otherEntity.primaryKey.fields.forEach((field, idx) => { _%> - <%= idx === 0 ? '' : ',' %>@JoinColumn(name = "<%= `${relationship.columnName}_${field.columnName}` %>")) + <%= idx === 0 ? '' : ',' %>@JoinColumn(name = "<%= `${relationship.columnName}_${field.columnName}` %>", referencedColumnName = "<%= field.columnName %>")) <%_ }); _%> <%= relationship.otherEntity.primaryKey.fields.length > 1 ? '}' : '' %> <%_ } _%> @@ -118,7 +127,10 @@ import org.hibernate.annotations.Type; <%_ } _%> <%_ if (relationship.id) { %> @MapsId - @JoinColumn(name = "<%= relationship.otherEntity.primaryKey.fields[0].columnName %>") + <% if (relationship.otherEntity.primaryKey.composite) { %>@JoinColumns({<% } %> + <%- relationship.otherEntity.primaryKey.fields.map(field => '@JoinColumn(name = "' + relationship.columnNamePrefix + field.columnName + '", referencedColumnName = "' + field.columnName + '"' + (relationship.otherEntity.primaryKey.composite ? '' : ', insertable = false, updatable = false') + ")").join(', ') %> + <% if (relationship.otherEntity.primaryKey.composite) { %>})<% } else { %> + <%_ } _%> <%_ } else { _%> @JoinColumn(unique = true) <%_ } _%> diff --git a/generators/entity-server/templates/src/main/java/package/domain/EntityId.java.ejs b/generators/entity-server/templates/src/main/java/package/domain/EntityId.java.ejs new file mode 100644 index 000000000000..bd9d18791e37 --- /dev/null +++ b/generators/entity-server/templates/src/main/java/package/domain/EntityId.java.ejs @@ -0,0 +1,98 @@ +<%# + Copyright 2013-2022 the original author or authors from the JHipster project. + + This file is part of the JHipster project, see https://www.jhipster.tech/ + for more information. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +-%> +package <%=packageName%>.domain; +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.metamodel.StaticMetamodel; +<%_ if (validation) { _%> +import javax.validation.constraints.*; +<%_ } _%> +import java.util.Objects; +<%_ if (primaryKey.fields.some(field => field.fieldType === 'UUID')) { _%> +import java.util.UUID; +<%_ } _%> + +@Embeddable +@StaticMetamodel(<%= entityClass %>Id.class) +public class <%= entityClass %>Id implements java.io.Serializable { +<%_ +primaryKey.fields.forEach(field => { _%> + + <%_ if (field.isEnum) { _%> + @Enumerated(EnumType.STRING) + <%_ } + if (field.fieldValidateRules && field.fieldValidateRules.includes('required')) { + required = true; + } + const fieldValidateRules = field.fieldValidateRules; + _%> + <%_ if (fieldValidateRules && fieldValidateRules.length > 0) { _%> + <%- include('../common/field_validators'); -%> + <%_ } _%> + @Column(name = "<%= field.columnName %>"<% if (field.fieldValidate === true) { %><% if (field.fieldValidateRules.includes('maxlength')) { %>, length = <%= field.fieldValidateRulesMaxlength %><% } %><% if (field.required) { %>, nullable = false<% } %><% if (field.unique) { %>, unique = true<% } %><% } %>) + private <%= field.fieldType %> <%= field.fieldName %>; +<%_ }) _%> + + public <%= entityClass %>Id(){} + + public <%= entityClass %>Id(<%= primaryKey.fields.map(field => field.fieldType + ' ' + field.fieldName).join(', ') %>){ +<%_ primaryKey.fields.forEach(field => { _%> + this.<%= field.fieldName %> = <%= field.fieldName %>; +<%_ }) _%> + } +<%_ primaryKey.fields.forEach(field => { _%> + + public <%= field.fieldType %> get<%= field.fieldNameCapitalized %>(){ + return this.<%= field.fieldName %>; + } + + public void set<%= field.fieldNameCapitalized %>(<%= field.fieldType %> <%= field.fieldName %>){ + this.<%= field.fieldName %> = <%= field.fieldName %>; + } +<%_ }) _%> + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof <%= entityClass %>Id)) { + return false; + } + + <%= entityClass %>Id <%= entityInstance %>Id = (<%= entityClass %>Id) o; + return <%- primaryKey.fields.map(f => `Objects.equals(${f.fieldName}, ${entityInstance}Id.${f.fieldName})`).join('\n && ') %>; + } + + @Override + public int hashCode() { + return Objects.hash(<%= primaryKey.fields.map(f => f.fieldName).join(', ')%>); + } + + // prettier-ignore + @Override + public String toString() { + return "<%= entityClass %>Id{" + + <%_ primaryKey.fields.forEach(field => { + const isNumeric = ['integer', 'long', 'float', 'double', 'bigdecimal'].includes(field.fieldType.toLowerCase()); _%> + ", <%= field.fieldName %>=<% if (! isNumeric) {%>'<% } %>" + get<%= field.fieldNameCapitalized %>() <% if (! isNumeric) { %>+ "'" <% } %>+ + <%_ }) _%> + "}"; + } +} diff --git a/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs b/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs index f1b4ef1b8d4d..f5f96b545386 100644 --- a/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/domain/enumeration/Enum.java.ejs @@ -32,8 +32,8 @@ public enum <%= enumName %> { enumValues.forEach((enumWithCustomValue, index) => { if (enumWithCustomValue.comment){ _%> <%= enumWithCustomValue.comment %> - <%_ } - if (enumWithCustomValue.name === enumWithCustomValue.value) { _%> + <%_ } + if (withoutCustomValues) { _%> <%= enumWithCustomValue.name %><% if (index < enumValues.length - 1) { %>,<% } else { %>;<% } %> <%_ } else { _%> <%= enumWithCustomValue.name %>("<%= enumWithCustomValue.value %>")<% if (index < enumValues.length - 1) { %>,<% } else { %>;<% } %> diff --git a/generators/entity-server/templates/src/main/java/package/repository/EntityRepository.java.ejs b/generators/entity-server/templates/src/main/java/package/repository/EntityRepository.java.ejs index 1a9791382684..a59ba8ae35a5 100644 --- a/generators/entity-server/templates/src/main/java/package/repository/EntityRepository.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/repository/EntityRepository.java.ejs @@ -49,6 +49,9 @@ import java.util.List; import java.util.Optional; <%_ } _%> <%_ } _%> +<%_ if (primaryKey.composite) { _%> +import <%=packageName%>.domain.<%=primaryKey.type%>; +<%_ } _%> <%_ if (primaryKey.typeUUID) { _%> import java.util.UUID; diff --git a/generators/entity-server/templates/src/main/java/package/service/EntityQueryService.java.ejs b/generators/entity-server/templates/src/main/java/package/service/EntityQueryService.java.ejs index 901607688c7a..3a11948e3e1e 100644 --- a/generators/entity-server/templates/src/main/java/package/service/EntityQueryService.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/service/EntityQueryService.java.ejs @@ -129,26 +129,26 @@ public class <%= serviceClassName %> extends QueryService<<%= persistClass %>> { if (criteria.getDistinct() != null) { specification = specification.and(distinct(criteria.getDistinct())); } - if (criteria.get<%= primaryKey.nameCapitalized %>() != null) { - specification = specification.and(<%= this.getSpecificationBuilder(primaryKey.type) %>(criteria.get<%= primaryKey.nameCapitalized %>(), <%= persistClass %>_.<%= primaryKey.name %>)); - } <%_ fields.forEach((field) => { - if (field.id || field.transient) return; if (this.isFilterableType(field.fieldType)) { _%> if (criteria.get<%= field.fieldInJavaBeanMethod %>() != null) { + <%_ if (field.id && primaryKey.composite) { _%> + specification = specification.and(buildSpecification(criteria.get<%= field.fieldInJavaBeanMethod %>(), root -> root.get(<%= persistClass %>_.id).get(<%= primaryKey.type %>_.<%= field.fieldName %>))); + <%_ } else { _%> specification = specification.and(<%= this.getSpecificationBuilder(field.fieldType) %>(criteria.get<%= field.fieldInJavaBeanMethod %>(), <%= persistClass %>_.<%= field.fieldName %>)); + <%_ } _%> } <%_ } }); -relationships.forEach((relationship) => { +relationships.forEach((relationship) => relationship.otherEntity.primaryKey.fields.forEach((field) => { const metamodelFieldName = (relationship.relationshipManyToMany || relationship.relationshipOneToMany) ? relationship.relationshipFieldNamePlural : relationship.relationshipFieldName; _%> -if (criteria.get<%= relationship.relationshipNameCapitalized %>Id() != null) { - specification = specification.and(buildSpecification(criteria.get<%= relationship.relationshipNameCapitalized %>Id(), - root -> root.join(<%= persistClass %>_.<%= metamodelFieldName %>, JoinType.LEFT).get(<%= relationship.otherEntity.persistClass %>_.<%= relationship.otherEntity.primaryKey.name %>))); +if (criteria.get<%= relationship.relationshipNameCapitalized %><%= field.fieldNameCapitalized %>() != null) { + specification = specification.and(buildSpecification(criteria.get<%= relationship.relationshipNameCapitalized %><%= field.fieldNameCapitalized %>(), + root -> root.join(<%= persistClass %>_.<%= metamodelFieldName %>, JoinType.LEFT)<%- relationship.otherEntity.primaryKey.composite ? `.get(${relationship.otherEntity.name}_.id).get(${relationship.otherEntity.primaryKey.type}_.${field.fieldName})` : `.get(${relationship.otherEntity.name}_.${field.fieldName})` %>)); } -<%_ }); /* forEach */ _%> +<%_ })); /* forEach */ _%> } return specification; } diff --git a/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs b/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs index c67280c761df..4e27db93b1a5 100644 --- a/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/service/EntityService.java.ejs @@ -51,6 +51,9 @@ import java.util.Optional; <%_ if (primaryKey.typeUUID) { _%> import java.util.UUID; <%_ } _%> +<%_ if (primaryKey.composite) { _%> +import <%=packageName%>.domain.<%=primaryKey.type%>; +<%_ } _%> /** * Service Interface for managing {@link <% if (dtoMapstruct) { %><%= entityAbsolutePackage %>.domain.<% } %><%= persistClass %>}. diff --git a/generators/entity-server/templates/src/main/java/package/service/criteria/EntityCriteria.java.ejs b/generators/entity-server/templates/src/main/java/package/service/criteria/EntityCriteria.java.ejs index 2a0cdf02ae08..8522badb4952 100644 --- a/generators/entity-server/templates/src/main/java/package/service/criteria/EntityCriteria.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/service/criteria/EntityCriteria.java.ejs @@ -30,8 +30,8 @@ fields.filter(field => !field.transient).forEach((field) => { fieldInJavaBeanMethod: field.fieldInJavaBeanMethod }); } }); -relationships.forEach((relationship) => { -const relationshipType = relationship.otherEntity.primaryKey.type; +relationships.forEach((relationship) => { relationship.otherEntity.primaryKey.fields.forEach(field => { +const relationshipType = field.fieldType; const referenceFilterType = '' + relationshipType + 'Filter'; // user has a String PK when using OAuth, so change relationships accordingly let oauthAwareReferenceFilterType = referenceFilterType; @@ -39,10 +39,10 @@ if (relationship.otherEntityUser && authenticationTypeOauth2) { oauthAwareReferenceFilterType = 'StringFilter'; } filterVariables.push({ filterType : oauthAwareReferenceFilterType, - name: relationship.relationshipFieldName + 'Id', + name: relationship.relationshipFieldName + field.fieldNameCapitalized, type: relationshipType, - fieldInJavaBeanMethod: relationship.relationshipNameCapitalized + 'Id' }); -}); + fieldInJavaBeanMethod: relationship.relationshipNameCapitalized + field.fieldNameCapitalized }); +})}); _%> /** * Criteria class for the {@link <%= entityAbsolutePackage %>.domain.<%= persistClass %>} entity. This class is used diff --git a/generators/entity-server/templates/src/main/java/package/service/dto/EntityDTO.java.ejs b/generators/entity-server/templates/src/main/java/package/service/dto/EntityDTO.java.ejs index e67e7d1f2647..9ebd4eb210ee 100644 --- a/generators/entity-server/templates/src/main/java/package/service/dto/EntityDTO.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/service/dto/EntityDTO.java.ejs @@ -141,7 +141,7 @@ _%> <%_ } _%> <%_ } _%> -<%_ const idNames = primaryKey ? [...primaryKey.fields.map(f => f.fieldName)] : [] _%> +<%_ const idNames = primaryKey ? (primaryKey.composite ? Array.from(new Set(primaryKey.fields.map(f => f.path[0]))) : [primaryKey.name]) : [] _%> @Override public boolean equals(Object o) { if (this == o) { diff --git a/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs b/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs index 9c96dbf98739..af055e82f7b3 100644 --- a/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/service/impl/EntityServiceImpl.java.ejs @@ -44,6 +44,9 @@ import <%= entityAbsolutePackage %>.repository.<%= mapsIdAssoc.otherEntityNameCa <%_ if (searchEngineElasticsearch) { _%> import <%= entityAbsolutePackage %>.repository.search.<%= entityClass %>SearchRepository; <%_ } _%> +<%_ if (primaryKey.composite) { _%> +import <%=packageName%>.domain.<%=primaryKey.type%>; +<%_ } _%> <%_ if (dtoMapstruct) { _%> import <%= entityAbsolutePackage %>.service.dto.<%= dtoClass %>; import <%= entityAbsolutePackage %>.service.mapper.<%= entityClass %>Mapper; diff --git a/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs b/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs index 2e95b793ff22..46462b5dfafd 100644 --- a/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs @@ -66,8 +66,7 @@ public interface <%= entityClass %>Mapper extends EntityMapper<<%= dtoClass %>, <%_ for (relationship of dtoRelationships) { _%> <%_ renMapAnotEnt = true; - let qualifiedByName = relationship.otherEntity.entityInstance + this._.upperFirst(relationship.otherEntityField); - qualifiedByName = qualifiedByName + (relationship.collection ? 'Set' : ''); + let qualifiedByName = relationship.otherEntity.entityInstance + this._.upperFirst(relationship.relatedField ? relationship.relatedField.propertyName : 'Id'); _%> @Mapping(target = "<%= relationship.propertyName %>", source = "<%= relationship.propertyName %>", qualifiedByName="<%= qualifiedByName %>") <%_ } _%> @@ -80,10 +79,16 @@ public interface <%= entityClass %>Mapper extends EntityMapper<<%= dtoClass %>, <%_ } _%> <%_ var renMapAnotDto = false; //Render Mapping Annotation during DTO to Entity conversion? _%> - <%_ if(primaryKey.ids.length > 1) { _%> + <%_ if(primaryKey.fields.length > 1) { _%> <%_ renMapAnotDto = true; _%> - <%_ for (const id of primaryKey.ids) { _%> - @Mapping(target = "id.<%= id.name %>", source = "<%= id.nameDotted %>") + <%_ for (const field of primaryKey.fields) { _%> + @Mapping(target = "id.<%= field.fieldName %>", source = "<%= field.fieldNameDotted %>") + <%_ } _%> + <%# I wouldn't expect to be needed the way @EmbeddedId works with "insertable = false, updatable = false" but it seems like it is so putting it here, this might not work for bigger depth, but for now I think its enough %> + <%_ for (const relationship of relationships.filter(r => r.id && !primaryKey.derived && r.otherEntity.primaryKey.fields.length > 1)) { _%> + <%_ for (const field of relationship.otherEntity.primaryKey.fields) { _%> + @Mapping(target = "<%= relationship.relationshipName %>.id.<%= field.fieldName %>", source = "<%= relationship.relationshipName %>.<%= field.fieldNameDotted %>") + <%_ } _%> <%_ } _%> <%_ } _%> <%_ for (relationship of dtoRelationships) { _%> @@ -100,25 +105,29 @@ public interface <%= entityClass %>Mapper extends EntityMapper<<%= dtoClass %>, <%= persistClass %> toEntity(<%= dtoClass %> <%= dtoInstance %>); <%_ } _%> <%_ for (const {otherEntity, relatedField, collection} of otherEntitiesFields) { _%> - <%_ const mapperName = otherEntity.entityInstance + this._.upperFirst(relatedField.propertyName); _%> + <%_ const mapperName = otherEntity.entityInstance + this._.upperFirst(relatedField ? relatedField.propertyName : 'Id'); _%> @Named("<%= mapperName %>") @BeanMapping(ignoreByDefault = true) - <%_ for (const field of otherEntity.primaryKey.fields) { _%> + <%_ if (otherEntity.primaryKey.composite) { _%> + <%_ for (const field of otherEntity.primaryKey.fields) { _%> + @Mapping(target = "<%= field.fieldNameDotted %>", source = "id.<%= field.fieldName %>") + <%_ if (field.relationshipsPath[0] && field.relationshipsPath.at(-1).relatedField) { + const relatedFieldNameDotted = `${field.relationshipsPath.map(r => r.relationshipName).join(".")}.${field.relationshipsPath.at(-1).relatedField.fieldName}` + if (relatedFieldNameDotted !== field.fieldNameDotted) { _%> + @Mapping(target = "<%= relatedFieldNameDotted %>", source = "<%= relatedFieldNameDotted %>") + <%_ } _%> + <%_ } _%> + <%_ } _%> + <%_ } else { _%> + <%_ for (const field of otherEntity.primaryKey.fields) { _%> @Mapping(target = "<%= field.propertyName %>", source = "<%= field.propertyName %>") + <%_ } _%> <%_ } _%> - <%_ if (!relatedField.id) { _%> + <%_ if (relatedField && !relatedField.id) { _%> @Mapping(target = "<%= relatedField.propertyName %>", source = "<%= relatedField.propertyName %>") <%_ } _%> <%- otherEntity.dtoClass %> toDto<%= this._.upperFirst(mapperName) %>(<%- otherEntity.persistClass %> <%= otherEntity.persistInstance %>); - <%_ if (collection) { %> - <%_ const collectionMapperName = otherEntity.entityInstance + this._.upperFirst(relatedField.propertyName) + 'Set'; _%> - - @Named("<%= collectionMapperName %>") - default Set<<%- otherEntity.dtoClass %>> toDto<%= this._.upperFirst(mapperName) %>Set(Set<<%- otherEntity.persistClass %>> <%= otherEntity.persistInstance %>) { - return <%= otherEntity.persistInstance %>.stream().map(this:: toDto<%= this._.upperFirst(mapperName) %>).collect(Collectors.toSet()); - } - <%_ } _%> <%_ } _%> <%_ if (uuidMapMethod) { _%> diff --git a/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs b/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs index dd05bcab88b8..421714721d56 100644 --- a/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/web/rest/EntityResource.java.ejs @@ -24,6 +24,11 @@ _%> <%_ if (!dtoMapstruct || serviceNo) { _%> import <%= entityAbsolutePackage %>.domain.<%= persistClass %>; <%_ } _%> +<%_ if (primaryKey.fields.length > 1) { _%> +import <%=packageName%>.domain.<%=primaryKey.type%>; +import java.util.Map; +import com.fasterxml.jackson.databind.ObjectMapper; +<%_ } _%> import <%= entityAbsolutePackage %>.repository.<%= entityClass %>Repository; <%_ if (!serviceNo) { _%> import <%= entityAbsolutePackage %>.service.<%= entityClass %>Service; @@ -41,7 +46,7 @@ import <%= entityAbsolutePackage %>.repository.UserRepository; import <%= packageName %>.web.rest.errors.BadRequestAlertException; <%_ if (dtoMapstruct) { _%> import <%= entityAbsolutePackage %>.service.dto.<%= dtoClass %>; - <%_ if (serviceNo) { _%> + <%_ if (serviceNo || primaryKey.composite) { _%> import <%= entityAbsolutePackage %>.service.mapper.<%= entityClass %>Mapper; <%_ } _%> <%_ } _%> @@ -136,6 +141,10 @@ import static org.elasticsearch.index.query.QueryBuilders.*; public class <%= entityClass %>Resource { private final Logger log = LoggerFactory.getLogger(<%= entityClass %>Resource.class); + +<%_ if(primaryKey.fields.length > 1) { _%> + private final ObjectMapper mapper = new ObjectMapper(); +<%_ } _%> <%_ if (!readOnly) { _%> <%_ let entityName = entityInstance; @@ -150,6 +159,7 @@ public class <%= entityClass %>Resource { <%_ const instanceType = restClass; const instanceName = restInstance; + const apiUrlPath = (key) => primaryKey.fields.length === 1 ? `${key}.get${primaryKey.nameCapitalized}()` : primaryKey.fields.map(f => `"${f.fieldName}=" + ${key}.${f.path.map(n => `get${this._.upperFirst(n)}()`).join('.')}`).join(' + ";" + '); const mapper = entityInstance + 'Mapper'; const entityToDtoReference = mapper + '::' + 'toDto'; _%><%- include('../../common/inject_template', {viaService: viaService, constructorName: entityClass + 'Resource', queryService: jpaMetamodelFiltering, isUsingMapsId: isUsingMapsId, mapsIdAssoc: mapsIdAssoc, isController: true}); -%> @@ -165,9 +175,27 @@ public class <%= entityClass %>Resource { @PostMapping("/<%= entityApiUrl %>") public <% if (reactive) { %>Mono<<% } %>ResponseEntity<<%= instanceType %>><% if (reactive) { %>><% } %> create<%= entityClass %>(<% if (validation) { %>@Valid <% } %>@RequestBody <%= instanceType %> <%= instanceName %>) throws URISyntaxException { log.debug("REST request to save <%= entityClass %> : {}", <%= instanceName %>); + <%_ if (primaryKey.fields.length === 1 && primaryKey.autoGenerate) { _%> if (<%= instanceName %>.get<%= primaryKey.nameCapitalized %>() != null) { throw new BadRequestAlertException("A new <%= entityInstance %> cannot already have an ID", ENTITY_NAME, "idexists"); } + <%_ } _%> +<%_ // TODO handle these cases when reactive (using switchIfEmpty flatMap... +if (!reactive) { _%> + <%_ if(primaryKey.fields.length === 1 && !primaryKey.autoGenerate) { _%> + if (<%= entityInstance %>Repository.existsById(<%= instanceName %>.get<%= primaryKey.nameCapitalized %>())) { + throw new BadRequestAlertException("This <%= entityInstance %> already exists", ENTITY_NAME, "idduplicate"); + } + <%_ } else if (primaryKey.composite) { _%> + <%= primaryKey.type %> id = <%= entityInstance %>Mapper.toEntity(<%= instanceName %>).getId(); + if (id == null) { + throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); + } + if (<%= entityInstance %>Service.findOne(id).isPresent()) { + throw new BadRequestAlertException("This <%= entityInstance %> already exists", ENTITY_NAME, "idduplicate"); + } + <%_ } _%> +<%_ } _%> <%_ if (saveUserSnapshot) { _%> <% for (const userRelationship of relationships.filter(rel => rel.otherEntity.builtInUser)) { %> <%_ if (userRelationship.collection) { _%> @@ -192,16 +220,16 @@ public class <%= entityClass %>Resource { <%_ if (reactive) { _%> .map(result -> { try { - return ResponseEntity.created(new URI("/api/<%= entityApiUrl %>/" + result.get<%= primaryKey.nameCapitalized %>())) - .headers(HeaderUtil.createEntityCreationAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, result.get<%= primaryKey.nameCapitalized %>()<% if (!primaryKey.typeString) { %>.toString()<% } %>)) + return ResponseEntity.created(new URI("/api/<%= entityApiUrl %>/" + <%- apiUrlPath('result') %>)) + .headers(HeaderUtil.createEntityCreationAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%- apiUrlPath('result') %><% if (!primaryKey.typeString) { %>.toString()<% } %>)) .body(result); } catch (URISyntaxException e) { throw new RuntimeException(e); } }); <%_ } else { _%> - return ResponseEntity.created(new URI("/api/<%= entityApiUrl %>/" + result.get<%= primaryKey.nameCapitalized %>())) - .headers(HeaderUtil.createEntityCreationAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, result.get<%= primaryKey.nameCapitalized %>()<% if (!primaryKey.typeString) { %>.toString()<% } %>)) + return ResponseEntity.created(new URI("/api/<%= entityApiUrl %>/" + <%- apiUrlPath('result') %>)) + .headers(HeaderUtil.createEntityCreationAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%- apiUrlPath('result') %><% if (!primaryKey.typeString) { %>.toString()<% } %>)) .body(result); <%_ } _%> } @@ -209,7 +237,11 @@ public class <%= entityClass %>Resource { /** * {@code PUT /<%= entityApiUrl %>/:<%= primaryKey.name %>} : Updates an existing <%= entityInstance %>. * +<%_ if(primaryKey.fields.length === 1) { _%> * @param <%= primaryKey.name %> the id of the <%= instanceName %> to save. +<%_ } else { _%> + * @param idMap a Map representation of the id of the <%= instanceName %> to save. +<%_ } _%> * @param <%= instanceName %> the <%= instanceName %> to update. * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated <%= instanceName %>, * or with status {@code 400 (Bad Request)} if the <%= instanceName %> is not valid, @@ -218,14 +250,27 @@ public class <%= entityClass %>Resource { */ @PutMapping("/<%= entityApiUrl %>/{<%= primaryKey.name %>}") public <% if (reactive) { %>Mono<<% } %>ResponseEntity<<%= instanceType %>><% if (reactive) { %>><% } %> update<%= entityClass %>( +<%_ if (primaryKey.fields.length === 1) { _%> @PathVariable(value = "<%= primaryKey.name %>", required = false) final <%= primaryKey.type %> <%= primaryKey.name %>, +<%_ } else { _%> + @MatrixVariable(pathVar = "id") Map idMap, +<%_ } _%> <% if (validation) { %>@Valid <% } %>@RequestBody <%= instanceType %> <%= instanceName %> ) throws URISyntaxException { +<%_ if(primaryKey.fields.length > 1) { _%> + final <%= primaryKey.type %> id = mapper.convertValue(idMap, <%= primaryKey.type %>.class); +<%_ } _%> log.debug("REST request to update <%= entityClass %> : {}, {}", <%= primaryKey.name %>, <%= instanceName %>); +<%_ if(primaryKey.fields.length === 1) { _%> if (<%= instanceName %>.get<%= primaryKey.nameCapitalized %>() == null) { throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); } +<%_ } _%> +<%_ if(primaryKey.fields.length === 1) { _%> if (!Objects.equals(<%= primaryKey.name %>, <%= instanceName %>.get<%= primaryKey.nameCapitalized %>())) { +<%_ } else {_%> + if (!Objects.equals(id, <%= entityInstance %>Mapper.toEntity(<%= instanceName %>).getId())) { +<%_ } _%> throw new BadRequestAlertException("Invalid ID", ENTITY_NAME, "idinvalid"); } @@ -259,13 +304,13 @@ public class <%= entityClass %>Resource { <%_ if (reactive) { _%> .switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND))) .map(result -> ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, result.get<%= primaryKey.nameCapitalized %>()<% if (!primaryKey.typeString) { %>.toString()<% } %>)) + .headers(HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%- apiUrlPath('result') %><% if (!primaryKey.typeString) { %>.toString()<% } %>)) .body(result) ); }); <%_ } else { _%> return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%= instanceName %>.get<%= primaryKey.nameCapitalized %>()<% if (!primaryKey.typeString) { %>.toString()<% } %>)) + .headers(HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%- apiUrlPath(instanceName) %><% if (!primaryKey.typeString) { %>.toString()<% } %>)) .body(result); <%_ } _%> } @@ -274,7 +319,11 @@ public class <%= entityClass %>Resource { /** * {@code PATCH /<%= entityApiUrl %>/:<%= primaryKey.name %>} : Partial updates given fields of an existing <%= entityInstance %>, field will ignore if it is null * +<%_ if(primaryKey.fields.length === 1) { _%> * @param <%= primaryKey.name %> the id of the <%= instanceName %> to save. +<%_ } else { _%> + * @param idMap a Map representation of the id of the <%= instanceName %> to save. +<%_ } _%> * @param <%= instanceName %> the <%= instanceName %> to update. * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated <%= instanceName %>, * or with status {@code 400 (Bad Request)} if the <%= instanceName %> is not valid, @@ -284,13 +333,26 @@ public class <%= entityClass %>Resource { */ @PatchMapping(value = "/<%= entityApiUrl %>/{<%= primaryKey.name %>}", consumes = {"application/json", "application/merge-patch+json"}) public <% if (reactive) { %>Mono<<% } %>ResponseEntity<<%= instanceType %>><% if (reactive) { %>><% } %> partialUpdate<%= entityClass %>( - @PathVariable(value = "<%= primaryKey.name %>", required = false) final <%= primaryKey.type %> <%= primaryKey.name %>, +<%_ if (primaryKey.fields.length === 1) { _%> + @PathVariable(value = "<%= primaryKey.name %>", required = false) final <%= primaryKey.type %> <%= primaryKey.name %>, +<%_ } else { _%> + @MatrixVariable(pathVar = "id") Map idMap, +<%_ } _%> <% if (validation) { %>@NotNull <% } %>@RequestBody <%= instanceType %> <%= instanceName %>) throws URISyntaxException { +<%_ if (primaryKey.fields.length > 1) { _%> + final <%= primaryKey.type %> id = mapper.convertValue(idMap, <%= primaryKey.type %>.class); +<%_ } _%> log.debug("REST request to partial update <%= entityClass %> partially : {}, {}", <%= primaryKey.name %>, <%= instanceName %>); +<%_ if(primaryKey.fields.length === 1) { _%> if (<%= instanceName %>.get<%= primaryKey.nameCapitalized %>() == null) { throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); } +<%_ } _%> +<%_ if(primaryKey.fields.length === 1) { _%> if (!Objects.equals(<%= primaryKey.name %>, <%= instanceName %>.get<%= primaryKey.nameCapitalized %>())) { +<%_ } else {_%> + if (!Objects.equals(id, <%= entityInstance %>Mapper.toEntity(<%= instanceName %>).getId())) { +<%_ } _%> throw new BadRequestAlertException("Invalid ID", ENTITY_NAME, "idinvalid"); } @@ -326,14 +388,14 @@ public class <%= entityClass %>Resource { return result .switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND))) .map(res -> ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, res.get<%= primaryKey.nameCapitalized %>()<% if (primaryKey.type !== 'String') { %>.toString()<% } %>)) + .headers(HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%- apiUrlPath('res') %><% if (!primaryKey.typeString) { %>.toString()<% } %>)) .body(res) ); }); <%_ } else { _%> return ResponseUtil.wrapOrNotFound( result, - HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%= instanceName %>.get<%= primaryKey.nameCapitalized %>()<% if (primaryKey.type !== 'String') { %>.toString()<% } %>) + HeaderUtil.createEntityUpdateAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, <%- apiUrlPath(instanceName) %><% if (!primaryKey.typeString) { %>.toString()<% } %>) ); <%_ } _%> } @@ -386,14 +448,21 @@ public class <%= entityClass %>Resource { /** * {@code GET /<%= entityApiUrl %>/:id} : get the "id" <%= entityInstance %>. * +<%_ if(primaryKey.fields.length === 1) { _%> * @param id the id of the <%= instanceName %> to retrieve. +<%_ } else { _%> + * @param idMap a Map representation of the id of the <%= instanceName %> to retrieve. +<%_ } _%> * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the <%= instanceName %>, or with status {@code 404 (Not Found)}. */ @GetMapping("/<%= entityApiUrl %>/{id}") <%_ if (databaseTypeSql && isUsingMapsId && !viaService) { _%> @Transactional(readOnly = true) <%_ } _%> - public <% if (reactive) { %>Mono<<% } %>ResponseEntity<<%= instanceType %>><% if (reactive) { %>><% } %> get<%= entityClass %>(@PathVariable <%= primaryKey.type %> id) { + public <% if (reactive) { %>Mono<<% } %>ResponseEntity<<%= instanceType %>><% if (reactive) { %>><% } %> get<%= entityClass %>(<% if (primaryKey.fields.length === 1) { %>@PathVariable <%= primaryKey.type %> id<% } else { %>@MatrixVariable(pathVar = "id") Map idMap<% } %>) { +<%_ if (primaryKey.fields.length > 1) { _%> + final <%= primaryKey.type %> id = mapper.convertValue(idMap, <%= primaryKey.type %>.class); +<%_ } _%> log.debug("REST request to get <%= entityClass %> : {}", id);<%- include('../../common/get_template', {viaService, returnDirectly:false, implementsEagerLoadApis}); -%> return ResponseUtil.wrapOrNotFound(<%= instanceName %>); } @@ -402,11 +471,18 @@ public class <%= entityClass %>Resource { /** * {@code DELETE /<%= entityApiUrl %>/:id} : delete the "id" <%= entityInstance %>. * +<%_ if(primaryKey.fields.length === 1) { _%> * @param id the id of the <%= instanceName %> to delete. +<%_ } else { _%> + * @param idMap a Map representation of the id of the <%= instanceName %> to delete. +<%_ } _%> * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}. */ @DeleteMapping("/<%= entityApiUrl %>/{id}") - public <% if (reactive) { %>Mono<<% } %>ResponseEntity<% if (reactive) { %>><% } %> delete<%= entityClass %>(@PathVariable <%= primaryKey.type %> id) { + public <% if (reactive) { %>Mono<<% } %>ResponseEntity<% if (reactive) { %>><% } %> delete<%= entityClass %>(<% if (primaryKey.fields.length === 1) { %>@PathVariable <%= primaryKey.type %> id<% } else { %>@MatrixVariable(pathVar = "id") Map idMap<% } %>) { +<%_ if (primaryKey.fields.length > 1) { _%> + final <%= primaryKey.type %> id = mapper.convertValue(idMap, <%= primaryKey.type %>.class); +<%_ } _%> log.debug("REST request to delete <%= entityClass %> : {}", id); <%- include('../../common/delete_template', {viaService: viaService, fromResource: true}); -%> <%_ if (reactive) { _%> @@ -420,7 +496,7 @@ public class <%= entityClass %>Resource { ); <%_ } _%> <%_ } else { _%> - return ResponseEntity.noContent().headers(HeaderUtil.createEntityDeletionAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, id<% if (!primaryKey.fields[0].fieldTypeString) { %>.toString()<% } %>)).build(); + return ResponseEntity.noContent().headers(HeaderUtil.createEntityDeletionAlert(applicationName, <%= enableTranslation %>, ENTITY_NAME, id<% if (primaryKey.type !== 'String') { %>.toString()<% } %>)).build(); <%_ } _%> } <%_ } _%> diff --git a/generators/entity-server/templates/src/test/java/package/domain/EntityTest.java.ejs b/generators/entity-server/templates/src/test/java/package/domain/EntityTest.java.ejs index f916211ec0ca..a62d00466957 100644 --- a/generators/entity-server/templates/src/test/java/package/domain/EntityTest.java.ejs +++ b/generators/entity-server/templates/src/test/java/package/domain/EntityTest.java.ejs @@ -27,16 +27,25 @@ import java.util.UUID; class <%= persistClass %>Test { +<%_ +function computeValue(entityNbr = 1) { + if (primaryKey.composite) { + return `new ${primaryKey.type}(${primaryKey.fields.map(field => this.getPrimaryKeyValue(field.fieldType, databaseType, entityNbr)).join(', ')})`; + } else { + return this.getPrimaryKeyValue(primaryKey.fields[0].fieldType, databaseType, entityNbr) + } +} +_%> @Test void equalsVerifier() throws Exception { TestUtil.equalsVerifier(<%= persistClass %>.class); <%_if (!embedded) { _%> <%= persistClass %> <%= persistInstance %>1 = new <%= persistClass %>(); - <%= persistInstance %>1.set<%= primaryKey.nameCapitalized %>(<% if (primaryKey.typeLong) { %>1L<% } else if (primaryKey.typeString) { %>"id1"<% } else if (primaryKey.typeUUID) { %>UUID.randomUUID()<% } %>); + <%= persistInstance %>1.set<%= primaryKey.nameCapitalized %>(<%- computeValue.bind(this)(1) %>); <%= persistClass %> <%= persistInstance %>2 = new <%= persistClass %>(); <%= persistInstance %>2.set<%= primaryKey.nameCapitalized %>(<%= persistInstance %>1.get<%= primaryKey.nameCapitalized %>()); assertThat(<%= persistInstance %>1).isEqualTo(<%= persistInstance %>2); - <%= persistInstance %>2.set<%= primaryKey.nameCapitalized %>(<% if (primaryKey.typeLong) { %>2L<% } else if (primaryKey.typeString) { %>"id2"<% } else if (primaryKey.typeUUID) { %>UUID.randomUUID()<% } %>); + <%= persistInstance %>2.set<%= primaryKey.nameCapitalized %>(<%- computeValue.bind(this)(2) %>); assertThat(<%= persistInstance %>1).isNotEqualTo(<%= persistInstance %>2); <%= persistInstance %>1.set<%= primaryKey.nameCapitalized %>(null); assertThat(<%= persistInstance %>1).isNotEqualTo(<%= persistInstance %>2); diff --git a/generators/entity-server/templates/src/test/java/package/service/dto/EntityDTOTest.java.ejs b/generators/entity-server/templates/src/test/java/package/service/dto/EntityDTOTest.java.ejs index d9843c00c429..1934f31faf3f 100644 --- a/generators/entity-server/templates/src/test/java/package/service/dto/EntityDTOTest.java.ejs +++ b/generators/entity-server/templates/src/test/java/package/service/dto/EntityDTOTest.java.ejs @@ -21,33 +21,49 @@ package <%= entityAbsolutePackage %>.service.dto; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import <%= packageName %>.web.rest.TestUtil; -<%_ -let id1; -let id2; -if (!embedded) { - id1 = this.getPrimaryKeyValue(primaryKey.type, databaseType, '1'); - id2 = this.getPrimaryKeyValue(primaryKey.type, databaseType, '2'); -} %> <%_ if (primaryKey && primaryKey.hasUUID) { _%> import java.util.UUID; <%_ } _%> +<%_ +const initDTO = (dtoEntity, entityNbr) => { +_%> + <%= dtoEntity.dtoClass %> <%= dtoEntity.dtoInstance %><%= entityNbr %> = new <%= dtoEntity.dtoClass %>(); + <%_ dtoEntity.fields.filter(f => f.id).forEach(f => { _%> + <%= dtoEntity.dtoInstance + entityNbr %>.set<%= f.fieldNameCapitalized %>(<%- this.getPrimaryKeyValue(f.fieldType, databaseType, entityNbr) %>); + <%_ }) _%> + <%_ dtoEntity.relationships.filter(r => r.id && !(r.relationshipType === 'one-to-one' && !dtoEntity.primaryKey.composite)).forEach(r => { _%> + <%- initDTO(r.otherEntity, entityNbr); _%> + <%= dtoEntity.dtoInstance + entityNbr %>.set<%= r.relationshipNameCapitalized %>(<%= r.otherEntity.dtoInstance + entityNbr %>); + <%_ }) +} +_%> class <%= dtoClass %>Test { @Test void dtoEqualsVerifier() throws Exception { TestUtil.equalsVerifier(<%= dtoClass %>.class); -<%_if (!embedded) { _%> - <%= dtoClass %> <%= dtoInstance %>1 = new <%= dtoClass %>(); - <%= dtoInstance %>1.set<%= primaryKey.nameCapitalized %>(<%- id1 %>); + <%_ if (!embedded) { _%> + <%- initDTO(entity, 1); _%> <%= dtoClass %> <%= dtoInstance %>2 = new <%= dtoClass %>(); assertThat(<%= dtoInstance %>1).isNotEqualTo(<%= dtoInstance %>2); - <%= dtoInstance %>2.set<%= primaryKey.nameCapitalized %>(<%= dtoInstance %>1.get<%= primaryKey.nameCapitalized %>()); +<%_ fields.filter(f => f.id).forEach(f => { _%> + <%= dtoInstance %>2.set<%= f.fieldNameCapitalized %>(<%= dtoInstance %>1.get<%= f.fieldNameCapitalized %>()); +<%_ }) _%> +<%_ relationships.filter(r => r.id && !(r.relationshipType === 'one-to-one' && !primaryKey.composite)).forEach(r => { _%> + <%= dtoInstance %>2.set<%= r.relationshipNameCapitalized %>(<%= r.otherEntity.dtoInstance %>1); +<%_ }) _%> assertThat(<%= dtoInstance %>1).isEqualTo(<%= dtoInstance %>2); - <%= dtoInstance %>2.set<%= primaryKey.nameCapitalized %>(<%- id2 %>); - assertThat(<%= dtoInstance %>1).isNotEqualTo(<%= dtoInstance %>2); - <%= dtoInstance %>1.set<%= primaryKey.nameCapitalized %>(null); - assertThat(<%= dtoInstance %>1).isNotEqualTo(<%= dtoInstance %>2); -<%_ } _%> + <%- initDTO(entity, 3); _%> + assertThat(<%= dtoInstance %>1).isNotEqualTo(<%= dtoInstance %>3); + <%= dtoClass %> <%= dtoInstance %>4 = new <%= dtoClass %>(); +<%_ fields.filter(f => f.id).forEach(f => { _%> + <%= dtoInstance %>4.set<%= f.fieldNameCapitalized %>(null); +<%_ }) _%> +<%_ relationships.filter(r => r.id && !(r.relationshipType === 'one-to-one' && !primaryKey.composite)).forEach(r => { _%> + <%= dtoInstance %>4.set<%= r.relationshipNameCapitalized %>(null); +<%_ }) _%> + assertThat(<%= dtoInstance %>1).isNotEqualTo(<%= dtoInstance %>4); + <%_ } _%> } } diff --git a/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs b/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs index 823980c2c249..5090140d633a 100644 --- a/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs +++ b/generators/entity-server/templates/src/test/java/package/web/rest/EntityResourceIT.java.ejs @@ -19,7 +19,7 @@ package <%= entityAbsolutePackage %>.web.rest; <%_ -const fieldsToTest = fields.filter(field => !field.id && !field.autoGenerate && !field.transient); +const fieldsToTest = fields.filter(field => !field.autoGenerate && !field.transient); let mapsIdEntity; let mapsIdEntityInstance; let mapsIdRepoInstance; @@ -55,13 +55,24 @@ let transactionalAnnotation = ''; if (databaseTypeSql && !reactive) { transactionalAnnotation = '\n @Transactional'; } - +const persistInstanceUrlId = primaryKey.fields.length === 1 ? + `${persistInstance}.get${primaryKey.nameCapitalized}()` : + primaryKey.fields.map(field => `"${field.fieldName}=" + ${persistInstance}.getId().get${field.fieldNameCapitalized}()`).join(' + ";" + '); +let generatedUrlId; +if(primaryKey.fields.length === 1) { + generatedUrlId = this.getJavaValueGeneratorForType(primaryKey.type); +} else { + generatedUrlId = primaryKey.fields.map(field => `"${field.fieldName}=" + ${this.getJavaValueGeneratorForType(field.fieldType)}`).join(' + ";" + ') +} _%> <%_ if (entityAbsolutePackage !== packageName) { _%> import <%= packageName %>.web.rest.TestUtil; <% } %> import <%= packageName %>.IntegrationTest; import <%= entityAbsolutePackage %>.domain.<%= persistClass %>; +<%_ if (primaryKey.composite) { _%> +import <%= entityAbsolutePackage %>.domain.<%= primaryKey.type %>; +<%_ } _%> <%_ var imported = []; for (relationship of relationships) { // import entities in required relationships @@ -190,7 +201,7 @@ import java.util.stream.Stream; <%_ } _%> <%_ } _%> import java.util.List; -<%_ if (fieldsContainUUID || primaryKey.typeString || otherEntityPrimaryKeyTypesIncludesUUID) { _%> +<%_ if (fieldsContainUUID || primaryKey.typeString || primaryKey.fields.map(f => f.fieldType).some(t => ['String', 'UUID'].includes(t)) || otherEntityPrimaryKeyTypesIncludesUUID) { _%> import java.util.UUID; <%_ } _%> <%_ if (!embedded && primaryKey.hasLong) { _%> @@ -526,13 +537,13 @@ if (field.fieldTypeString || field.blobContentTypeText) { <%_ } else { _%> <%= relationship.otherEntity.persistClass %> <%= otherEntityName %>; <%_ if (databaseTypeSql && !reactive) { _%> - <%_ if (!isUsingMapsId || fieldStatus !== "UPDATED_") { _%> + <%_ if (fields.some(f => f.id) || fieldStatus !== "UPDATED_") { _%> if (TestUtil.findAll(em, <%= relationship.otherEntity.persistClass %>.class).isEmpty()) { <%_ } _%> <%= otherEntityName %> = <%= createEntityPrefix %><%= otherEntityNameCapitalized %>ResourceIT.create<% if (fieldStatus === 'UPDATED_') { %>Updated<% } %>Entity(em)<%= createEntityPostfix %>; em.persist(<%= otherEntityName %>); em.flush(); - <%_ if (!isUsingMapsId || fieldStatus !== "UPDATED_") { _%> + <%_ if (fields.some(f => f.id) || fieldStatus !== "UPDATED_") { _%> } else { <%= otherEntityName %> = TestUtil.findAll(em, <%= relationship.otherEntity.persistClass %>.class).get(0); } @@ -552,6 +563,11 @@ if (field.fieldTypeString || field.blobContentTypeText) { <%_ } _%> <%_ alreadyGeneratedEntities.push(otherEntityName) _%> <%_ } _%> + <%_ } _%> + <%_ if (primaryKey.composite) { _%> + <%= persistInstance %>.setId(new <%= primaryKey.type %>( + <%- primaryKey.fields.map(field => [persistInstance, ...field.path.map(p => `get${this._.upperFirst(p)}()`)].join('.')).join(',') %> + )); <%_ } _%> return <%= persistInstance %>; } @@ -669,14 +685,14 @@ _%> <%_ if (isUsingMapsId) { _%> // Validate the id for MapsId, the ids must be same - assertThat(test<%= entityClass %>.get<%= primaryKey.nameCapitalized %>()).isEqualTo(<%_ if (dtoMapstruct) { _%><%= dtoInstance %><%_ } else { _%>test<%= entityClass %><%_ } _%>.get<%= mapsIdEntity %>().get<%= primaryKey.nameCapitalized %>()); + assertThat(test<%= entityClass %>.get<%= primaryKey.nameCapitalized %>()).isEqualTo(test<%= entityClass %>.get<%= mapsIdEntity %>().get<%= mapsIdAssoc.otherEntity.primaryKey.nameCapitalized %>()); <%_ } _%> } @Test<%= transactionalAnnotation %> void create<%= entityClass %>WithExistingId() throws Exception { // Create the <%= entityClass %> with an existing ID - <%_ if (primaryKey.typeUUID && databaseTypeSql) { _%> + <%_ if ((primaryKey.typeUUID && databaseTypeSql) || primaryKey.composite || !primaryKey.autoGenerate) { _%> <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; <%_ } else { _%> <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<% if (primaryKey.typeUUID) { %>UUID.randomUUID()<% } else if (primaryKey.typeLong) { %>1L<% } else { %>"existing_id"<% } %>); @@ -716,7 +732,9 @@ _%> <%_ } _%> } - <%_ if (databaseTypeSql && isUsingMapsId) { _%> + <%# this is not doable with composite keys, without drastically chaging the logic, since we would need to read the id from url, + set it in entity instead of validating it, then using the relationnships to update the DB, and it might not work since we usable insertable/updatable false %> + <%_ if (databaseTypeSql && isUsingMapsId && primaryKey.fields.length === 1) { _%> @Test<%= transactionalAnnotation %> void update<%= entityClass %>MapsIdAssociationWithNewId() throws Exception { // Initialize the database @@ -766,7 +784,7 @@ _%> .exchange() .expectStatus().isOk(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%_ if (dtoMapstruct) { _%>updated<%= dtoClass %> <%_ } else { _%> updated<%= persistClass %> <%_ } _%>.get<%= primaryKey.nameCapitalized %>())<% if (testsNeedCsrf) { %>.with(csrf())<% }%> + rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%- persistInstanceUrlId %>)<% if (testsNeedCsrf) { %>.with(csrf())<% }%> .contentType(MediaType.APPLICATION_JSON) .content(TestUtil.convertObjectToJsonBytes(<%_ if (dtoMapstruct) { _%>updated<%= dtoClass %> <%_ } else { _%> updated<%= persistClass %> <%_ } _%>))) .andExpect(status().isOk()); @@ -844,11 +862,6 @@ _%> @Test<%= transactionalAnnotation %> void getAll<%= entityClassPlural %>AsStream() { // Initialize the database - <%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= field.fieldNameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> - <%_ } _%> <%= entityInstance %>Repository.save(<%= persistInstance %>)<%= callBlock %>; List<<%= persistClass %>> <%= entityInstance %>List = webTestClient.get().uri(ENTITY_API_URL) @@ -886,11 +899,6 @@ _%> @Test<%= transactionalAnnotation %> void getAll<%= entityClassPlural %>() <% if (!reactive) { %>throws Exception <% } %>{ // Initialize the database -<%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= field.fieldNameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> -<%_ } _%> <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; // Get all the <%= entityInstance %>List @@ -906,7 +914,7 @@ _%> .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) <%_ } _%> -<%_ if (databaseTypeSql || databaseTypeMongodb || databaseTypeCouchbase || databaseTypeCassandra) { _%> +<%_ if ((databaseTypeSql || databaseTypeMongodb || databaseTypeCouchbase || databaseTypeCassandra) && !primaryKey.composite) { _%> <%= !reactive ? '.andExpect(' : '.' %>jsonPath("$.[*].<%= primaryKey.name %>").value(hasItem(<%= idValue %>))<%= !reactive ? ')' : '' %><%_ } _%><% for (field of fieldsToTest) { %> <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> <%= !reactive ? '.andExpect(' : '.' %>jsonPath("$.[*].<%= field.fieldName %>ContentType").value(hasItem(<%= 'DEFAULT_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE))<%= !reactive ? ')' : '' %> @@ -973,11 +981,6 @@ _%> @Test<%= transactionalAnnotation %> void get<%= entityClass %>() <% if (!reactive) { %>throws Exception <% } %>{ // Initialize the database -<%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= field.fieldNameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> -<%_ } _%> <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; // Get the <%= entityInstance %> @@ -989,11 +992,11 @@ _%> .expectHeader().contentType(MediaType.APPLICATION_JSON) .expectBody() <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(get(ENTITY_API_URL_ID, <%= persistInstance %>.get<%= primaryKey.nameCapitalized %>())) + rest<%= entityClass %>MockMvc.perform(get(ENTITY_API_URL_ID, <%- persistInstanceUrlId %>)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) <%_ } _%> -<%_ if (databaseTypeSql || databaseTypeMongodb || databaseTypeCouchbase || databaseTypeCassandra) { _%> +<%_ if ((databaseTypeSql || databaseTypeMongodb || databaseTypeCouchbase || databaseTypeCassandra) && !primaryKey.composite) { _%> <%= !reactive ? '.andExpect(' : '.' %>jsonPath("$.<%= primaryKey.name %>").value(<%= reactive ? 'is(' : '' %><%= idValue %>))<%_ } _%><% for (field of fieldsToTest) { %> <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> <%= !reactive ? '.andExpect(' : '.' %>jsonPath("$.<%= field.fieldName %>ContentType").value(<%= reactive ? 'is(' : '' %><%= 'DEFAULT_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE)) @@ -1013,6 +1016,7 @@ _%> if (!field.fieldTypeString) { %>.toString()<% } %>))<%_ } _%>; } <%_ if (jpaMetamodelFiltering) { %> + <%_ if (primaryKey.fields.length === 1) { _%> @Test<%= transactionalAnnotation %> void get<%= entityClassPlural %>ByIdFiltering() <% if (!reactive) { %>throws Exception <% } %>{ @@ -1024,14 +1028,15 @@ _%> default<%= entityClass %>ShouldBeFound("<%= primaryKey.name %>.equals=" + id); default<%= entityClass %>ShouldNotBeFound("<%= primaryKey.name %>.notEquals=" + id); - <%_ if (primaryKey.typeLong) { _%> + <%_ if (primaryKey.typeLong) { _%> default<%= entityClass %>ShouldBeFound("<%= primaryKey.name %>.greaterThanOrEqual=" + id); default<%= entityClass %>ShouldNotBeFound("<%= primaryKey.name %>.greaterThan=" + id); default<%= entityClass %>ShouldBeFound("<%= primaryKey.name %>.lessThanOrEqual=" + id); default<%= entityClass %>ShouldNotBeFound("<%= primaryKey.name %>.lessThan=" + id); - <%_ } _%> + <%_ } _%> } + <%_ } _%> <%_ fieldsToTest.forEach((searchBy) => { /* we can't filter by all the fields. */_%> <%_ if (this.isFilterableType(searchBy.fieldType)) { _%> @@ -1169,14 +1174,17 @@ _%> @Test<%= transactionalAnnotation %> void getAll<%= entityClassPlural %>By<%= relationship.relationshipNameCapitalized %>IsEqualToSomething() <% if (!reactive) { %>throws Exception <% } %>{ + <% const differentEntity = relationship.otherEntityNameCapitalized !== name; %> <%_ if ((relationship.relationshipValidate && relationship.relationshipOneToOne) || relationship.id) { _%> // Get already existing entity <%= relationship.otherEntity.persistClass %> <%= relationship.relationshipFieldName %> = <%= persistInstance %>.get<%= relationship.relationshipNameCapitalized %>(); <%_ } else { _%> + // Initialize the database <%_ if (databaseTypeSql && !reactive) { _%> + <%# we persist first in case there is a relationship wth same entity %> + em.persist(<%= persistInstance %>); <%= relationship.otherEntity.persistClass %> <%= relationship.relationshipFieldName %>; if (TestUtil.findAll(em, <%= relationship.otherEntity.persistClass %>.class).isEmpty()) { - <%= entityInstance %>Repository.saveAndFlush(<%= persistInstance %>); <%= relationship.relationshipFieldName %> = <%= createEntityPrefix %><%= relationship.otherEntityNameCapitalized %>ResourceIT.createEntity(em); } else { <%= relationship.relationshipFieldName %> = TestUtil.findAll(em, <%= relationship.otherEntity.persistClass %>.class).get(0); @@ -1185,7 +1193,6 @@ _%> <%= relationship.otherEntity.persistClass %> <%= relationship.relationshipFieldName %> = <%= relationship.otherEntityNameCapitalized %>ResourceIT.createEntity(em); <%_ } _%> em.persist(<%= relationship.relationshipFieldName %>); - em.flush(); <%_ if (relationship.relationshipManyToMany || relationship.relationshipOneToMany) { _%> <%= persistInstance %>.add<%= relationship.relationshipNameCapitalized %>(<%= relationship.relationshipFieldName %>); <%_ } else { _%> @@ -1196,20 +1203,29 @@ _%> <%_ } _%> <%_ } _%> <%= entityInstance %>Repository.saveAndFlush(<%= persistInstance %>); - <%= relationship.otherEntity.primaryKey.type %> <%= relationship.relationshipFieldName %>Id = <%= relationship.relationshipFieldName %>.get<%= relationship.otherEntity.primaryKey.nameCapitalized %>(); - - // Get all the <%= entityInstance %>List where <%= relationship.relationshipFieldName %> equals to <%= relationship.relationshipFieldName %>Id - default<%= entityClass %>ShouldBeFound("<%= relationship.relationshipFieldName %>Id.equals=" + <%= relationship.relationshipFieldName %>Id); - - <%_ - const initInvalidPrimaryKey = { - 'String' : '"invalid-id"', - 'Long' : '(' + relationship.relationshipFieldName + 'Id + 1)', - 'UUID' : 'UUID.randomUUID()' - }[relationship.otherEntity.primaryKey.type]; + <%_ const field = relationship.otherEntity.primaryKey.fields[0]; + const filterName = `${relationship.relationshipName}${field.fieldNameCapitalized}`; + let filterValue = relationship.relationshipName; + if (relationship.otherEntity.primaryKey.composite) { + filterValue += `.getId()`; + } + filterValue += `.get${field.fieldNameCapitalized}()`; + const filterType = field.fieldType; _%> - // Get all the <%= entityInstance %>List where <%= relationship.relationshipFieldName %> equals to <%- initInvalidPrimaryKey %> - default<%= entityClass %>ShouldNotBeFound("<%= relationship.relationshipFieldName %>Id.equals=" + <%- initInvalidPrimaryKey %>); + + // Get all the <%= entityInstance %>List where <%= filterName %> equals to <%= filterValue %> + default<%= entityClass %>ShouldBeFound("<%= filterName %>.equals=" + <%= filterValue %>); + + <%_ + const initInvalidPrimaryKey = { + 'String' : '"invalid-id"', + 'Long' : '(' + filterValue + ' + 1)', + 'Integer' : '(' + filterValue + ' + 1)', + 'UUID' : 'UUID.randomUUID()' + }[filterType]; + _%> + // Get all the <%= entityInstance %>List where <%= filterName %> equals to <%- initInvalidPrimaryKey %> + default<%= entityClass %>ShouldNotBeFound("<%= filterName %>.equals=" + <%- initInvalidPrimaryKey %>); } <%_ }); _%> @@ -1224,7 +1240,7 @@ _%> .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON) .expectBody() - .jsonPath("$.[*].<%= primaryKey.name %>").value(hasItem(<%= idValue %>))<% for (field of fieldsToTest) { %> + <%_ if (!primaryKey.composite) { _%>.jsonPath("$.[*].<%= primaryKey.name %>").value(hasItem(<%= idValue %>))<%_ } _%><% for (field of fieldsToTest) { %> <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> .jsonPath("$.[*].<%= field.fieldName %>ContentType").value(hasItem(<%= 'DEFAULT_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE)) <%_ } _%> @@ -1260,7 +1276,7 @@ _%> 'UUID' : '.toString()' }[primaryKey.type] || ''; _%> - .andExpect(jsonPath("$.[*].<%= primaryKey.name %>").value(hasItem(<%= persistInstance %>.get<%= primaryKey.nameCapitalized %>()<%= primaryKeyConversion %>)))<% fieldsToTest.forEach((field) => { %> + <%_ if (!primaryKey.composite) { _%>.andExpect(jsonPath("$.[*].<%= primaryKey.name %>").value(hasItem(<%= persistInstance %>.get<%= primaryKey.nameCapitalized %>()<%= primaryKeyConversion %>)))<%_ } _%><% fieldsToTest.forEach((field) => { %> <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> .andExpect(jsonPath("$.[*].<%= field.fieldName %>ContentType").value(hasItem(<%= 'DEFAULT_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE))) <%_ } _%> @@ -1329,12 +1345,12 @@ _%> void getNonExisting<%= entityClass %>() <% if (!reactive) { %>throws Exception <% } %>{ // Get the <%= entityInstance %> <%_ if (reactive) { _%> - webTestClient.get().uri(ENTITY_API_URL_ID, <% if (primaryKey.typeLong || primaryKey.typeString) { %>Long.MAX_VALUE<% } else if (primaryKey.typeUUID) { %>UUID.randomUUID().toString()<% } %>) + webTestClient.get().uri(ENTITY_API_URL_ID, <% if (primaryKey.typeLong || primaryKey.typeString) { %>Long.MAX_VALUE<% } else if (primaryKey.typeUUID) { %>UUID.randomUUID().toString()<% } else { %><%- persistInstanceUrlId %><% } %>) .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isNotFound(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(get(ENTITY_API_URL_ID, <% if (primaryKey.typeLong || primaryKey.typeString) { %>Long.MAX_VALUE<% } else if (primaryKey.typeUUID) { %>UUID.randomUUID().toString()<% } %>)) + rest<%= entityClass %>MockMvc.perform(get(ENTITY_API_URL_ID, <% if (primaryKey.typeLong || primaryKey.typeString) { %>Long.MAX_VALUE<% } else if (primaryKey.typeUUID) { %>UUID.randomUUID().toString()<% } else { %><%- persistInstanceUrlId %><% } %>)) .andExpect(status().isNotFound()); <%_ } _%> } @@ -1343,11 +1359,6 @@ _%> @Test<%= transactionalAnnotation %> void putExisting<%= entityClass %>() throws Exception { // Initialize the database - <%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= field.fieldNameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> - <%_ } _%> <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; int databaseSizeBeforeUpdate = <%= entityInstance %>Repository.findAll()<%= callListBlock %>.size(); @@ -1363,11 +1374,11 @@ _%> em.detach(updated<%= persistClass %>); <%_ } _%> <%_ if (fluentMethods && fieldsToTest.length > 0) { _%> - updated<%= persistClass %><% for (field of fieldsToTest) { %> + updated<%= persistClass %><% for (field of fieldsToTest.filter(f => !f.id)) { %> .<%= field.fieldName %>(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>)<% if (field.fieldTypeBinary && !field.blobContentTypeText) { %> .<%= field.fieldName %>ContentType(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE)<% } %><% } %>; <%_ } else { _%> - <%_ for (field of fieldsToTest) { _%> + <%_ for (field of fieldsToTest.filter(f => !f.id)) { _%> updated<%= persistClass %>.set<%= field.fieldInJavaBeanMethod %>(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> updated<%= persistClass %>.set<%= field.fieldInJavaBeanMethod %>ContentType(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE); @@ -1385,7 +1396,7 @@ _%> .exchange() .expectStatus().isOk(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%= (dtoMapstruct ? dtoInstance : 'updated' + persistClass) %>.get<%= primaryKey.nameCapitalized %>())<% if (testsNeedCsrf) { %>.with(csrf())<% } %> + rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%- persistInstanceUrlId %>)<% if (testsNeedCsrf) { %>.with(csrf())<% } %> .contentType(MediaType.APPLICATION_JSON) .content(TestUtil.convertObjectToJsonBytes(<%= (dtoMapstruct ? dtoInstance : 'updated' + persistClass) %>))) .andExpect(status().isOk()); @@ -1400,14 +1411,14 @@ _%> <%= persistClass %> test<%= entityClass %> = <%= entityInstance %>List.get(<%= entityInstance %>List.size() - 1); <%_ for (const field of fieldsToTest) { _%> <%_ if (field.fieldTypeZonedDateTime) { _%> - assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); <%_ } else if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> - assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); - assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>ContentType()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE); + assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>ContentType()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE); <%_ } else if (field.fieldTypeBigDecimal) { _%> - assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualByComparingTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualByComparingTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); <%_ } else { _%> - assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); <%_ } _%> <%_ } _%> <%_ if (searchEngineElasticsearch) { _%> @@ -1418,14 +1429,14 @@ _%> <%= persistClass %> test<%= entityClass %>Search = <%= entityInstance %>SearchList.get(searchDatabaseSizeAfter - 1); <%_ for (const field of fieldsToTest) { _%> <%_ if (field.fieldTypeZonedDateTime) { _%> - assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); <%_ } else if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> - assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); - assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>ContentType()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE); + assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>ContentType()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE); <%_ } else if (field.fieldTypeBigDecimal) { _%> - assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualByComparingTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualByComparingTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); <%_ } else { _%> - assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= 'UPDATED_' + field.fieldNameUnderscored.toUpperCase() %>); + assertThat(test<%= entityClass %>Search.get<%= field.fieldInJavaBeanMethod %>()).isEqualTo(<%= (field.id ? 'DEFAULT_' : 'UPDATED_') + field.fieldNameUnderscored.toUpperCase() %>); <%_ } _%> <%_ } _%> }); @@ -1438,7 +1449,7 @@ _%> <%_ if (searchEngineElasticsearch) { _%> int searchDatabaseSizeBefore = IterableUtil.sizeOf(<%= entityInstance %>SearchRepository.findAll()<%= callListBlock %>); <%_ } _%> - <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForType(primaryKey.type) %>); + <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForPrimaryKey(primaryKey) %>); <%_ if (dtoMapstruct) { _%> // Create the <%= entityClass %> @@ -1453,7 +1464,7 @@ _%> .exchange() .expectStatus().isBadRequest(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%= restInstance %>.get<%= primaryKey.nameCapitalized %>())<% if (testsNeedCsrf) { %>.with(csrf())<% }%> + rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%- persistInstanceUrlId %>)<% if (testsNeedCsrf) { %>.with(csrf())<% } %> .contentType(MediaType.APPLICATION_JSON) .content(TestUtil.convertObjectToJsonBytes(<%= restInstance %>))) .andExpect(status().isBadRequest()); @@ -1478,7 +1489,7 @@ _%> <%_ if (searchEngineElasticsearch) { _%> int searchDatabaseSizeBefore = IterableUtil.sizeOf(<%= entityInstance %>SearchRepository.findAll()<%= callListBlock %>); <%_ } _%> - <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForType(primaryKey.type) %>); + <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForPrimaryKey(primaryKey) %>); <%_ if (dtoMapstruct) { _%> // Create the <%= entityClass %> @@ -1487,13 +1498,13 @@ _%> <%_ } _%> // If url ID doesn't match entity ID, it will throw BadRequestAlertException <%_ if (reactive) { _%> - webTestClient.put().uri(ENTITY_API_URL_ID, <%- this.getJavaValueGeneratorForType(primaryKey.type) %>) + webTestClient.put().uri(ENTITY_API_URL_ID, <%- generatedUrlId %>) .contentType(MediaType.APPLICATION_JSON) .bodyValue(TestUtil.convertObjectToJsonBytes(<%= restInstance %>)) .exchange() .expectStatus().isBadRequest(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%- this.getJavaValueGeneratorForType(primaryKey.type) %>)<% if (testsNeedCsrf) { %>.with(csrf())<% } %> + rest<%= entityClass %>MockMvc.perform(put(ENTITY_API_URL_ID, <%- generatedUrlId %>)<% if (testsNeedCsrf) { %>.with(csrf())<% } %> .contentType(MediaType.APPLICATION_JSON) .content(TestUtil.convertObjectToJsonBytes(<%= restInstance %>))) .andExpect(status().isBadRequest()); @@ -1517,7 +1528,7 @@ _%> <%_ if (searchEngineElasticsearch) { _%> int searchDatabaseSizeBefore = IterableUtil.sizeOf(<%= entityInstance %>SearchRepository.findAll()<%= callListBlock %>); <%_ } _%> - <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForType(primaryKey.type) %>); + <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForPrimaryKey(primaryKey) %>); <%_ if (dtoMapstruct) { _%> // Create the <%= entityClass %> @@ -1562,29 +1573,19 @@ _%> @Test<%= transactionalAnnotation %> void partialUpdate<%= entityClass %>WithPatch() throws Exception { // Initialize the database - <%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= field.fieldNameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> - <%_ } _%> <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; - <%_ const fieldsToIncludeInPartialPatchTest = fieldsToTest.map(field => prepareFieldForPatchTest(field, () => faker.datatype.boolean())); _%> -<%- include('/partials/it_patch_update.partial.java.ejs', {fields: fieldsToIncludeInPartialPatchTest, saveMethod, callBlock, callListBlock}); -%> + <%_ const fieldsToIncludeInPartialPatchTest = fieldsToTest.map(field => prepareFieldForPatchTest(field, () => field.id ? false : faker.datatype.boolean())); _%> +<%- include('/partials/it_patch_update.partial.java.ejs', {fields: fieldsToIncludeInPartialPatchTest, saveMethod, callBlock, callListBlock, persistInstanceUrlId}); -%> } @Test<%= transactionalAnnotation %> void fullUpdate<%= entityClass %>WithPatch() throws Exception { // Initialize the database - <%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= field.fieldNameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> - <%_ } _%> <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; - <% const fieldsToIncludeInFullPatchTest = fieldsToTest.map(field => prepareFieldForPatchTest(field, () => true)); %> -<%- include('/partials/it_patch_update.partial.java.ejs', {fields: fieldsToIncludeInFullPatchTest, saveMethod, callBlock, callListBlock}); -%> + <% const fieldsToIncludeInFullPatchTest = fieldsToTest.map(field => prepareFieldForPatchTest(field, () => !field.id)); %> +<%- include('/partials/it_patch_update.partial.java.ejs', {fields: fieldsToIncludeInFullPatchTest, saveMethod, callBlock, callListBlock, persistInstanceUrlId}); -%> } @Test<%= transactionalAnnotation %> @@ -1593,7 +1594,7 @@ _%> <%_ if (searchEngineElasticsearch) { _%> int searchDatabaseSizeBefore = IterableUtil.sizeOf(<%= entityInstance %>SearchRepository.findAll()<%= callListBlock %>); <%_ } _%> - <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForType(primaryKey.type) %>); + <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForPrimaryKey(primaryKey) %>); <%_ if (dtoMapstruct) { _%> // Create the <%= entityClass %> @@ -1608,7 +1609,7 @@ _%> .exchange() .expectStatus().isBadRequest(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, <%= restInstance %>.get<%= primaryKey.nameCapitalized %>())<% if (testsNeedCsrf) { %>.with(csrf())<% }%> + rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, <%- persistInstanceUrlId %>)<% if (testsNeedCsrf) { %>.with(csrf())<% }%> .contentType("application/merge-patch+json") .content(TestUtil.convertObjectToJsonBytes(<%= restInstance %>))) .andExpect(status().isBadRequest()); @@ -1632,7 +1633,7 @@ _%> <%_ if (searchEngineElasticsearch) { _%> int searchDatabaseSizeBefore = IterableUtil.sizeOf(<%= entityInstance %>SearchRepository.findAll()<%= callListBlock %>); <%_ } _%> - <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForType(primaryKey.type) %>); + <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForPrimaryKey(primaryKey) %>); <%_ if (dtoMapstruct) { _%> // Create the <%= entityClass %> @@ -1641,13 +1642,13 @@ _%> <%_ } _%> // If url ID doesn't match entity ID, it will throw BadRequestAlertException <%_ if (reactive) { _%> - webTestClient.patch().uri(ENTITY_API_URL_ID, <%- this.getJavaValueGeneratorForType(primaryKey.type) %>) + webTestClient.patch().uri(ENTITY_API_URL_ID, <%- generatedUrlId %>) .contentType(MediaType.valueOf("application/merge-patch+json")) .bodyValue(TestUtil.convertObjectToJsonBytes(<%= restInstance %>)) .exchange() .expectStatus().isBadRequest(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, <%- this.getJavaValueGeneratorForType(primaryKey.type) %>)<% if (testsNeedCsrf) { %>.with(csrf())<% } %> + rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, <%- generatedUrlId %>)<% if (testsNeedCsrf) { %>.with(csrf())<% } %> .contentType("application/merge-patch+json") .content(TestUtil.convertObjectToJsonBytes(<%= restInstance %>))) .andExpect(status().isBadRequest()); @@ -1671,7 +1672,7 @@ _%> <%_ if (searchEngineElasticsearch) { _%> int searchDatabaseSizeBefore = IterableUtil.sizeOf(<%= entityInstance %>SearchRepository.findAll()<%= callListBlock %>); <%_ } _%> - <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForType(primaryKey.type) %>); + <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForPrimaryKey(primaryKey) %>); <%_ if (dtoMapstruct) { _%> // Create the <%= entityClass %> @@ -1708,11 +1709,6 @@ _%> @Test<%= transactionalAnnotation %> void delete<%= entityClass %>() <% if (!reactive) { %>throws Exception <% } %>{ // Initialize the database - <%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= primaryKey.nameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> - <%_ } _%> <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; <%_ if (searchEngineElasticsearch) { _%> <%= entityInstance %>Repository.save(<%= persistInstance %>)<%= callBlock %>; @@ -1732,7 +1728,7 @@ _%> .exchange() .expectStatus().isNoContent(); <%_ } else { _%> - rest<%= entityClass %>MockMvc.perform(delete(ENTITY_API_URL_ID, <%= persistInstance %>.get<%= primaryKey.nameCapitalized %>()<% if (primaryKey.typeUUID && databaseTypeSql) { %>.toString()<% } %>)<% if (testsNeedCsrf) { %>.with(csrf())<% }%> + rest<%= entityClass %>MockMvc.perform(delete(ENTITY_API_URL_ID, <%- persistInstanceUrlId %>)<% if (testsNeedCsrf) { %>.with(csrf())<% } %> .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isNoContent()); <%_ } _%> @@ -1758,11 +1754,6 @@ _%> @Test<%= transactionalAnnotation %> void search<%= entityClass %>() <% if (!reactive) { %>throws Exception <% } %>{ // Initialize the database - <%_ if (!primaryKey.derived) { _%> - <%_ for (field of primaryKey.fields.filter(f => !f.autoGenerateByRepository)) { _%> - <%= persistInstance %>.set<%= field.fieldNameCapitalized %>(<%- this.getJavaValueGeneratorForType(field.fieldType) %>); - <%_ } _%> - <%_ } _%> <%= persistInstance %> = <%= entityInstance %>Repository.<%= saveMethod %>(<%= persistInstance %>)<%= callBlock %>; <%_ if (searchEngineElasticsearch) { _%> <%= entityInstance %>SearchRepository.save(<%= persistInstance %>)<%= callBlock %>; @@ -1783,7 +1774,7 @@ _%> .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) <%_ } _%> - <%_ if (databaseTypeSql || databaseTypeMongodb || databaseTypeCouchbase || databaseTypeCassandra) { _%> + <%_ if ((databaseTypeSql || databaseTypeMongodb || databaseTypeCouchbase || databaseTypeCassandra) && !primaryKey.composite) { _%> <%= !reactive ? '.andExpect(' : '.' %>jsonPath("$.[*].<%= primaryKey.name %>").value(hasItem(<%= idValue %>))<%= !reactive ? ')' : '' %><%_ } _%><% for (field of fieldsToTest) { %> <%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%> <%= !reactive ? '.andExpect(' : '.' %>jsonPath("$.[*].<%= field.fieldName %>ContentType").value(hasItem(<%= 'DEFAULT_' + field.fieldNameUnderscored.toUpperCase() %>_CONTENT_TYPE))<%= !reactive ? ')' : '' %> diff --git a/generators/generator-base-private.js b/generators/generator-base-private.js index 59939eafa345..049ed05485d1 100644 --- a/generators/generator-base-private.js +++ b/generators/generator-base-private.js @@ -1179,33 +1179,55 @@ module.exports = class JHipsterBasePrivateGenerator extends Generator { * @return {String} test sample */ generateTypescriptTestEntity(references, additionalFields = {}) { - const entries = references - .map(reference => { - if (reference.field) { - const field = reference.field; - const { fieldIsEnum, fieldType, fieldTypeTimed, fieldTypeLocalDate, fieldWithContentType, fieldName, contentTypeFieldName } = - field; + return this.jsonToString(this.generateTypescriptTestEntityObject(references, additionalFields)); + } - const fakeData = field.generateFakeData('ts'); - if (fieldWithContentType) { - return [ - [fieldName, fakeData], - [contentTypeFieldName, "'unknown'"], - ]; - } - if (fieldIsEnum) { - return [[fieldName, `${fieldType}[${fakeData}]`]]; - } - if (fieldTypeTimed || fieldTypeLocalDate) { - return [[fieldName, `dayjs(${fakeData})`]]; + generateTypescriptTestEntityObject(references, additionalFields = {}) { + const relationships = references.filter(r => r.relationship).map(r => r.relationship); + const result = {}; + relationships.forEach(relationship => { + result[relationship.relationshipName] = this.generateTypescriptTestEntityObject( + [...relationship.otherEntity.fields.filter(f => f.id), ...relationship.otherEntity.relationships.filter(r => r.id)].map( + f => f.reference + ) + ); + }); + return Object.assign( + result, + additionalFields, + ...references + .filter(r => !r.relationship) + .map(reference => { + if (reference.field) { + const field = reference.field; + const { fieldIsEnum, fieldType, fieldTypeTimed, fieldTypeLocalDate, fieldWithContentType, fieldName, contentTypeFieldName } = + field; + + const fakeData = field.generateFakeData('ts'); + if (fieldWithContentType) { + return { [fieldName]: fakeData, [contentTypeFieldName]: "'unknown'" }; + } + if (fieldIsEnum) { + return { [fieldName]: `${fieldType}[${fakeData}]` }; + } + if (fieldTypeTimed || fieldTypeLocalDate) { + return { [fieldName]: `dayjs(${fakeData})` }; + } + return { [fieldName]: fakeData }; } - return [[fieldName, fakeData]]; - } - return [[reference.name, this.generateTestEntityId(reference.type, 'random', false)]]; - }) - .flat(); + return { [reference.name]: this.generateTestEntityId(reference.type, 'random', false) }; + }) + ); + } + + /** + * This is different from JSON.stringify as it handle values a string content + */ + jsonToString(json) { return `{ - ${[...entries, ...Object.entries(additionalFields)].map(([key, value]) => `${key}: ${value}`).join(',\n ')} + ${[...Object.entries(json)] + .map(([key, value]) => `${key}: ${value && typeof value === 'object' ? this.jsonToString(value) : value}`) + .join(',\n ')} }`; } @@ -1343,6 +1365,13 @@ module.exports = class JHipsterBasePrivateGenerator extends Generator { throw new Error(`Java type ${type} does not have a random generator implemented`); } + getJavaValueGeneratorForPrimaryKey(primaryKey) { + if (primaryKey.composite) { + return `new ${primaryKey.type}(${primaryKey.fields.map(f => this.getJavaValueGeneratorForType(f.fieldType)).join(', ')})`; + } + return this.getJavaValueGeneratorForType(primaryKey.type); + } + /** * Get a root folder name for entity * @param {string} clientRootFolder diff --git a/generators/server/__snapshots__/generator.spec.mjs.snap b/generators/server/__snapshots__/generator.spec.mjs.snap index 1de534c46ee9..d5f19a08fc77 100644 --- a/generators/server/__snapshots__/generator.spec.mjs.snap +++ b/generators/server/__snapshots__/generator.spec.mjs.snap @@ -606,6 +606,10 @@ Object { "file": "package/config/LoggingAspectConfiguration.java", "renameTo": [Function], }, + Object { + "file": "package/config/MatrixVariableConfiguration.java", + "renameTo": [Function], + }, Object { "file": "package/config/WebConfigurer.java", "renameTo": [Function], diff --git a/generators/server/__snapshots__/needles.spec.mjs.snap b/generators/server/__snapshots__/needles.spec.mjs.snap index 1b1f12657516..3c6c49b8dd0f 100644 --- a/generators/server/__snapshots__/needles.spec.mjs.snap +++ b/generators/server/__snapshots__/needles.spec.mjs.snap @@ -146,6 +146,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, diff --git a/generators/server/files.js b/generators/server/files.js index d24e0b02d3cb..87ef2517bd1b 100644 --- a/generators/server/files.js +++ b/generators/server/files.js @@ -869,6 +869,10 @@ const baseServerFiles = { file: 'package/config/LoggingAspectConfiguration.java', renameTo: generator => `${generator.javaDir}config/LoggingAspectConfiguration.java`, }, + { + file: 'package/config/MatrixVariableConfiguration.java', + renameTo: generator => `${generator.javaDir}config/MatrixVariableConfiguration.java`, + }, { file: 'package/config/WebConfigurer.java', renameTo: generator => `${generator.javaDir}config/WebConfigurer.java` }, ], }, diff --git a/generators/server/templates/src/main/java/package/config/MatrixVariableConfiguration.java.ejs b/generators/server/templates/src/main/java/package/config/MatrixVariableConfiguration.java.ejs new file mode 100644 index 000000000000..c9eaa1a901c4 --- /dev/null +++ b/generators/server/templates/src/main/java/package/config/MatrixVariableConfiguration.java.ejs @@ -0,0 +1,47 @@ +<%# + Copyright 2013-2022 the original author or authors from the JHipster project. + + This file is part of the JHipster project, see https://www.jhipster.tech/ + for more information. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +-%> +package <%=packageName%>.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.web.firewall.StrictHttpFirewall; +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.util.UrlPathHelper; + +/** + * Configure server to allow Matrix Variables + */ +@Configuration +public class MatrixVariableConfiguration implements WebMvcConfigurer { + + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + UrlPathHelper urlPathHelper = new UrlPathHelper(); + urlPathHelper.setRemoveSemicolonContent(false); + configurer.setUrlPathHelper(urlPathHelper); + } + + @Bean + public StrictHttpFirewall httpFirewall() { + StrictHttpFirewall firewall = new StrictHttpFirewall(); + firewall.setAllowSemicolon(true); + return firewall; + } +} diff --git a/generators/server/templates/src/test/java/package/web/rest/TestUtil.java.ejs b/generators/server/templates/src/test/java/package/web/rest/TestUtil.java.ejs index 5fed2a5d3a50..484e401f5197 100644 --- a/generators/server/templates/src/test/java/package/web/rest/TestUtil.java.ejs +++ b/generators/server/templates/src/test/java/package/web/rest/TestUtil.java.ejs @@ -19,8 +19,10 @@ package <%= packageName %>.web.rest; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; @@ -67,11 +69,12 @@ public final class TestUtil { private static final ObjectMapper mapper = createObjectMapper(); private static ObjectMapper createObjectMapper() { - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false); - mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); - mapper.registerModule(new JavaTimeModule()); - return mapper; + return JsonMapper.builder() + .configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false) + .configure(MapperFeature.USE_ANNOTATIONS, false) + .serializationInclusion(JsonInclude.Include.NON_EMPTY) + .addModule(new JavaTimeModule()) + .build(); } /** diff --git a/jdl/jhipster/reserved-keywords/postgresql.js b/jdl/jhipster/reserved-keywords/postgresql.js index 5344e24ac766..5a98fe903c35 100644 --- a/jdl/jhipster/reserved-keywords/postgresql.js +++ b/jdl/jhipster/reserved-keywords/postgresql.js @@ -116,4 +116,5 @@ module.exports = [ 'WHERE', 'WINDOW', 'WITH', + 'VALUE', ]; diff --git a/package.json b/package.json index c7693102ce4f..e6b02d5bfce8 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,8 @@ "./cli": "./dist/cli/index.mjs", "./package.json": "./package.json", "./generators": "./dist/lib/constants/generators.mjs", + "./generators/*.js": "./dist/generators/*.js", + "./generators/*.cjs": "./dist/generators/*.cjs", "./generators/*": "./dist/generators/*/index.mjs", "./priorities": "./dist/lib/constants/priorities.mjs", "./jdl/": "./dist/jdl/" diff --git a/test/__snapshots__/app-client-custom-path.spec.js.snap b/test/__snapshots__/app-client-custom-path.spec.js.snap index 7ae6cdcb82f5..6bba1d8a2b32 100644 --- a/test/__snapshots__/app-client-custom-path.spec.js.snap +++ b/test/__snapshots__/app-client-custom-path.spec.js.snap @@ -164,6 +164,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -1570,6 +1573,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, diff --git a/test/__snapshots__/app.spec.js.snap b/test/__snapshots__/app.spec.js.snap index d326f398ce0d..e2f09ab55244 100644 --- a/test/__snapshots__/app.spec.js.snap +++ b/test/__snapshots__/app.spec.js.snap @@ -161,6 +161,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -637,6 +640,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -2096,6 +2102,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -3514,6 +3523,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -4890,6 +4902,9 @@ Object { "src/main/java/com/test/reactui/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/test/reactui/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/test/reactui/config/ReactorConfiguration.java": Object { "stateCleared": "modified", }, @@ -5564,6 +5579,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -6964,6 +6982,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -8376,6 +8397,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -9809,6 +9833,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -11215,6 +11242,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -12219,6 +12249,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -13631,6 +13664,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -15010,6 +15046,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -16386,6 +16425,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, diff --git a/test/__snapshots__/server.spec.js.snap b/test/__snapshots__/server.spec.js.snap index a7327c106ddf..bd433177913f 100644 --- a/test/__snapshots__/server.spec.js.snap +++ b/test/__snapshots__/server.spec.js.snap @@ -146,6 +146,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -730,6 +733,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -1335,6 +1341,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, diff --git a/test/blueprint/__snapshots__/app-blueprint.spec.js.snap b/test/blueprint/__snapshots__/app-blueprint.spec.js.snap index 76dec64f7cda..f3c2e07de4fc 100644 --- a/test/blueprint/__snapshots__/app-blueprint.spec.js.snap +++ b/test/blueprint/__snapshots__/app-blueprint.spec.js.snap @@ -164,6 +164,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, @@ -1576,6 +1579,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, diff --git a/test/blueprint/__snapshots__/scoped-blueprint.spec.js.snap b/test/blueprint/__snapshots__/scoped-blueprint.spec.js.snap index d84b1822aea4..346574eb1dc0 100644 --- a/test/blueprint/__snapshots__/scoped-blueprint.spec.js.snap +++ b/test/blueprint/__snapshots__/scoped-blueprint.spec.js.snap @@ -164,6 +164,9 @@ Object { "src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java": Object { "stateCleared": "modified", }, + "src/main/java/com/mycompany/myapp/config/MatrixVariableConfiguration.java": Object { + "stateCleared": "modified", + }, "src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java": Object { "stateCleared": "modified", }, diff --git a/test/utils-entity.spec.js b/test/utils-entity.spec.js index 77a20a52463b..9495f86cd0e4 100644 --- a/test/utils-entity.spec.js +++ b/test/utils-entity.spec.js @@ -257,14 +257,12 @@ describe('entity utilities', () => { }); it('should prepare correct relationship id ids', () => { - const field = entity4.primaryKey.ids[1]; + const field = entity4.primaryKey.fields[1]; expect(field).to.deep.include({ name: 'otherEntity1Id', nameCapitalized: 'OtherEntity1Id', - nameDotted: 'otherEntity1.id', - nameDottedAsserted: 'otherEntity1!.id!', - setter: 'setOtherEntity1Id', - getter: 'getOtherEntity1Id', + fieldNameDotted: 'otherEntity1.id', + fieldNameDottedAsserted: 'otherEntity1!.id!', }); }); @@ -285,14 +283,12 @@ describe('entity utilities', () => { }); it('should prepare correct relationship id with derived primaryKey field ids', () => { - const field = entity4.primaryKey.ids[2]; + const field = entity4.primaryKey.fields[2]; expect(field).to.deep.include({ name: 'otherEntity3Uuid', nameCapitalized: 'OtherEntity3Uuid', - nameDotted: 'otherEntity3.uuid', - nameDottedAsserted: 'otherEntity3!.uuid!', - setter: 'setOtherEntity3Uuid', - getter: 'getOtherEntity3Uuid', + fieldNameDotted: 'otherEntity3.uuid', + fieldNameDottedAsserted: 'otherEntity3!.uuid!', }); }); }); diff --git a/utils/entity.js b/utils/entity.js index b2ad21f7f7d0..f218cd3769ac 100644 --- a/utils/entity.js +++ b/utils/entity.js @@ -284,6 +284,9 @@ function prepareEntityServerForTemplates(entity) { } else { entity.entityInstanceDbSafe = entity.entityInstance; } + if (isReservedTableName(entity.entityTableName, entity.prodDatabaseType) && entity.jhiPrefix) { + entity.entityTableName = `${entity.jhiPrefix}_${entity.entityTableName}`; + } } function derivedPrimaryKeyProperties(primaryKey) { @@ -381,7 +384,7 @@ function prepareEntityPrimaryKeyForTemplates(entityWithConfig, generator, enable // MapsId copy the id from the relationship. autoGenerate: true, get fields() { - return this.derivedFields; + return this.derivedFields.map(field => preparePrimaryKeyFields(field)); }, get derivedFields() { return relationshipId.derivedPrimaryKey.derivedFields; @@ -406,7 +409,7 @@ function prepareEntityPrimaryKeyForTemplates(entityWithConfig, generator, enable return relationshipId.otherEntity.primaryKey.composite; }, get ids() { - return this.fields.map(field => fieldToId(field)); + return this.fields; }, }; } else { @@ -439,7 +442,7 @@ function prepareEntityPrimaryKeyForTemplates(entityWithConfig, generator, enable ownFields: idFields, // Fields declared and inherited get fields() { - return [...this.ownFields, ...this.derivedFields]; + return [...this.ownFields, ...this.derivedFields].map(field => preparePrimaryKeyFields(field)); }, get autoGenerate() { return this.composite ? false : this.fields[0].autoGenerate; @@ -449,41 +452,29 @@ function prepareEntityPrimaryKeyForTemplates(entityWithConfig, generator, enable return this.relationships.map(rel => rel.derivedPrimaryKey.derivedFields).flat(); }, get ids() { - return this.fields.map(field => fieldToId(field)); + return this.fields; }, }; } return entityWithConfig; } -function fieldToId(field) { - return { - field, - get name() { - return field.fieldName; - }, - get nameCapitalized() { - return field.fieldNameCapitalized; - }, - get nameDotted() { +function preparePrimaryKeyFields(field) { + Object.defineProperty(field, 'fieldNameDotted', { + get() { return field.derivedPath ? field.derivedPath.join('.') : field.fieldName; }, - get nameDottedAsserted() { + enumerable: true, + configurable: true, + }); + Object.defineProperty(field, 'fieldNameDottedAsserted', { + get() { return field.derivedPath ? `${field.derivedPath.join('!.')}!` : `${field.fieldName}!`; }, - get setter() { - return `set${this.nameCapitalized}`; - }, - get getter() { - return (field.fieldType === BOOLEAN ? 'is' : 'get') + this.nameCapitalized; - }, - get autoGenerate() { - return !!field.autoGenerate; - }, - get relationshipsPath() { - return field.relationshipsPath; - }, - }; + enumerable: true, + configurable: true, + }); + return field; } /** diff --git a/utils/index.js b/utils/index.js index 86fff3c0f6f3..dd3c22b5c56c 100644 --- a/utils/index.js +++ b/utils/index.js @@ -46,6 +46,9 @@ module.exports = { if (key === 'derivedFields') { return '[derivedFields]'; } + if (key === 'relationshipsPath') { + return '[relationshipsPath]'; + } return value; }, 4