From d0b5a9686e6806dbcb2b0a34c84a3c1755236d2c Mon Sep 17 00:00:00 2001 From: Jan Wedding Date: Mon, 13 Jan 2025 18:42:54 +0100 Subject: [PATCH] Add support for plain Time fields Fix #28406 --- .../_entityFile_-update.component.html.ejs | 3 +++ .../base-application/support/field-utils.ts | 2 ++ .../support/prepare-entity.ts | 3 ++- .../base-application/support/prepare-field.ts | 9 ++++++++- .../bootstrap-application/generator.spec.ts | 13 ++++++++++++ .../client/support/entity-definition.ts | 3 ++- generators/client/support/types-utils.spec.ts | 1 + generators/entity/prompts.ts | 20 ++++++++++++++++--- .../domain/_persistClass_.java.jhi.ejs | 2 ++ .../incremental-liquibase.spec.ts.snap | 12 +++++++++++ generators/liquibase/support/prepare-field.ts | 13 +++++++++++- .../resources/config/liquibase/master.xml.ejs | 7 +++++++ .../_entityFile_-update.tsx.ejs | 5 +++++ .../support/build-specification-mapper.ts | 2 ++ generators/spring-boot/generator.ts | 4 ++++ .../criteria/_entityClass_Criteria.java.ejs | 9 +++++++-- .../service/dto/_dtoClass_.java.ejs | 3 +++ .../config/JacksonConfiguration.java.ejs | 15 +++++++++++++- .../web/rest/_entityClass_ResourceIT.java.ejs | 10 ++++++++++ .../config/cql/changelog/added_entity.cql.ejs | 2 ++ ..._persistClass_.java.jhi.elastic_search.ejs | 2 ++ .../_entityClass_RowMapper_reactive.java.ejs | 2 ++ .../_entityFile_-update.vue.ejs | 2 ++ lib/application/field-types.ts | 1 + lib/jhipster/field-types.ts | 2 ++ lib/types/application/entity.d.ts | 1 + lib/types/application/field.d.ts | 1 + .../samples/.jhipster/FieldTestEntity.json | 2 ++ .../FieldTestInfiniteScrollEntity.json | 2 ++ ...eldTestMapstructAndServiceClassEntity.json | 2 ++ .../.jhipster/FieldTestPaginationEntity.json | 2 ++ ...TestServiceClassAndJpaFilteringEntity.json | 2 ++ .../.jhipster/FieldTestServiceImplEntity.json | 2 ++ 33 files changed, 151 insertions(+), 10 deletions(-) diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs index ff7a7422b8bb..b00382a388bd 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs @@ -99,6 +99,9 @@ _%> <%_ } else if (field.fieldTypeBoolean) { _%> [readonly]="true"<% } %>/> + <%_ } else if (field.fieldTypeLocalTime) { _%> + [readonly]="true"<% } %>/> <%_ } else { _%> [readonly]="editForm.get('<%= primaryKey.name %>')!.disabled"<% } else if (readonly) { %> [readonly]="true"<% } %>/> diff --git a/generators/base-application/support/field-utils.ts b/generators/base-application/support/field-utils.ts index aced4dcc6aa9..90644820b2f6 100644 --- a/generators/base-application/support/field-utils.ts +++ b/generators/base-application/support/field-utils.ts @@ -33,6 +33,7 @@ const { STRING, UUID, ZONED_DATE_TIME, + LOCAL_TIME, IMAGE_BLOB, ANY_BLOB, TEXT_BLOB, @@ -50,6 +51,7 @@ export function fieldIsEnum(fieldType) { LOCAL_DATE, INSTANT, ZONED_DATE_TIME, + LOCAL_TIME, DURATION, UUID, BOOLEAN, diff --git a/generators/base-application/support/prepare-entity.ts b/generators/base-application/support/prepare-entity.ts index 620751eadb3c..6741696bf549 100644 --- a/generators/base-application/support/prepare-entity.ts +++ b/generators/base-application/support/prepare-entity.ts @@ -52,7 +52,7 @@ const NO_MAPPER = MapperTypes.NO; const { CASSANDRA, COUCHBASE, NEO4J, SQL, MONGODB } = databaseTypes; -const { INSTANT, ZONED_DATE_TIME, DURATION, LOCAL_DATE, BIG_DECIMAL } = fieldTypes.CommonDBTypes; +const { INSTANT, ZONED_DATE_TIME, DURATION, LOCAL_DATE, BIG_DECIMAL, LOCAL_TIME } = fieldTypes.CommonDBTypes; const { BYTES, BYTE_BUFFER } = fieldTypes.RelationalOnlyDBTypes; const { IMAGE, TEXT } = fieldTypes.BlobTypes; @@ -549,6 +549,7 @@ export function preparePostEntityCommonDerivedProperties(entity: Entity) { entity.anyFieldIsZonedDateTime = fieldsType.includes(ZONED_DATE_TIME); entity.anyFieldIsInstant = fieldsType.includes(INSTANT); + entity.anyFieldIsLocalTime = fieldsType.includes(LOCAL_TIME); entity.anyFieldIsDuration = fieldsType.includes(DURATION); entity.anyFieldIsLocalDate = fieldsType.includes(LOCAL_DATE); entity.anyFieldIsBigDecimal = fieldsType.includes(BIG_DECIMAL); diff --git a/generators/base-application/support/prepare-field.ts b/generators/base-application/support/prepare-field.ts index c4964454025f..94e139431ce4 100644 --- a/generators/base-application/support/prepare-field.ts +++ b/generators/base-application/support/prepare-field.ts @@ -51,6 +51,7 @@ const { ANY_BLOB, TEXT_BLOB, BLOB, + LOCAL_TIME, } = CommonDBTypes; const { BYTES, BYTE_BUFFER } = RelationalOnlyDBTypes; @@ -162,12 +163,17 @@ function generateFakeDataForField( max: field.fieldValidateRulesMax ?? 32767, min: field.fieldValidateRulesMin ?? 0, }); - } else if ([INSTANT, ZONED_DATE_TIME, LOCAL_DATE].includes(field.fieldType)) { + } else if ([INSTANT, ZONED_DATE_TIME, LOCAL_DATE, LOCAL_TIME].includes(field.fieldType)) { // Iso: YYYY-MM-DDTHH:mm:ss.sssZ const date = faker.date.recent({ days: 1, refDate: changelogDate }); originalData = date.toISOString(); if (field.fieldType === LOCAL_DATE) { data = originalData.split('T')[0]; + } else if (field.fieldType === LOCAL_TIME) { + // time without seconds by default + const timeWithoutMilliseconds = originalData.split('T')[1].split('.')[0]; + // default time input fields are set to support HH:mm. Some databases require :00 during loading of fake data to detect the datatype. + data = `${timeWithoutMilliseconds.substring(0, timeWithoutMilliseconds.lastIndexOf(':'))}:00`; } else if (type === 'json-serializable') { data = date; } else { @@ -262,6 +268,7 @@ function _derivedProperties(field) { fieldTypeTimed: fieldType === ZONED_DATE_TIME || fieldType === INSTANT, fieldTypeCharSequence: fieldType === STRING || fieldType === UUID || fieldType === TEXT_BLOB, fieldTypeTemporal: fieldType === ZONED_DATE_TIME || fieldType === INSTANT || fieldType === LOCAL_DATE, + fieldTypeLocalTime: fieldType === LOCAL_TIME, fieldValidationRequired: validationRules.includes(REQUIRED), fieldValidationMin: validationRules.includes(MIN), fieldValidationMinLength: validationRules.includes(MINLENGTH), diff --git a/generators/bootstrap-application/generator.spec.ts b/generators/bootstrap-application/generator.spec.ts index 80b5f3d4589d..3c2dc59a32c9 100644 --- a/generators/bootstrap-application/generator.spec.ts +++ b/generators/bootstrap-application/generator.spec.ts @@ -184,6 +184,7 @@ describe(`generator - ${generator}`, () => { "anyFieldIsDuration": false, "anyFieldIsInstant": false, "anyFieldIsLocalDate": false, + "anyFieldIsLocalTime": false, "anyFieldIsTimeDerived": false, "anyFieldIsUUID": true, "anyFieldIsZonedDateTime": false, @@ -300,6 +301,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": false, @@ -398,6 +400,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": true, @@ -498,6 +501,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": true, @@ -588,6 +592,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": true, @@ -678,6 +683,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": true, @@ -773,6 +779,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": true, @@ -864,6 +871,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": false, @@ -946,6 +954,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": true, @@ -1161,6 +1170,7 @@ describe(`generator - ${generator}`, () => { "anyFieldIsDuration": false, "anyFieldIsInstant": false, "anyFieldIsLocalDate": false, + "anyFieldIsLocalTime": false, "anyFieldIsTimeDerived": false, "anyFieldIsUUID": true, "anyFieldIsZonedDateTime": false, @@ -1267,6 +1277,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": false, @@ -1536,6 +1547,7 @@ describe(`generator - ${generator}`, () => { "anyFieldIsDuration": false, "anyFieldIsInstant": false, "anyFieldIsLocalDate": false, + "anyFieldIsLocalTime": false, "anyFieldIsTimeDerived": false, "anyFieldIsUUID": true, "anyFieldIsZonedDateTime": false, @@ -1642,6 +1654,7 @@ describe(`generator - ${generator}`, () => { "fieldTypeInstant": false, "fieldTypeInteger": false, "fieldTypeLocalDate": false, + "fieldTypeLocalTime": false, "fieldTypeLong": false, "fieldTypeNumeric": false, "fieldTypeString": false, diff --git a/generators/client/support/entity-definition.ts b/generators/client/support/entity-definition.ts index 57cc2ad71a37..d33dd490fb81 100644 --- a/generators/client/support/entity-definition.ts +++ b/generators/client/support/entity-definition.ts @@ -39,6 +39,7 @@ const { ZONED_DATE_TIME: TYPE_ZONED_DATE_TIME, INSTANT: TYPE_INSTANT, DURATION: TYPE_DURATION, + LOCAL_TIME: TYPE_TIME, } = dbTypes.CommonDBTypes; const TYPE_BYTES = dbTypes.RelationalOnlyDBTypes.BYTES; @@ -85,7 +86,7 @@ const generateEntityClientFields = ( tsType = 'boolean'; } else if ([TYPE_INTEGER, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_BIG_DECIMAL].includes(fieldType)) { tsType = 'number'; - } else if ([TYPE_STRING, TYPE_UUID, TYPE_DURATION, TYPE_BYTES, TYPE_BYTE_BUFFER].includes(fieldType)) { + } else if ([TYPE_STRING, TYPE_UUID, TYPE_DURATION, TYPE_BYTES, TYPE_BYTE_BUFFER, TYPE_TIME].includes(fieldType)) { tsType = 'string'; if ([TYPE_BYTES, TYPE_BYTE_BUFFER].includes(fieldType) && field.fieldTypeBlobContent !== 'text') { variablesWithTypes.push(`${fieldName}ContentType?: ${nullable ? 'string | null' : 'string'}`); diff --git a/generators/client/support/types-utils.spec.ts b/generators/client/support/types-utils.spec.ts index 49f904ac8f76..517d3a7f7a9d 100644 --- a/generators/client/support/types-utils.spec.ts +++ b/generators/client/support/types-utils.spec.ts @@ -24,6 +24,7 @@ describe('generator - client - support - type-utils', () => { "Instant": "dayjs.Dayjs", "Integer": "number", "LocalDate": "dayjs.Dayjs", + "LocalTime": "string", "Long": "number", "String": "string", "TextBlob": "string", diff --git a/generators/entity/prompts.ts b/generators/entity/prompts.ts index 07eb986cd1b6..d7f5a74084d4 100644 --- a/generators/entity/prompts.ts +++ b/generators/entity/prompts.ts @@ -44,8 +44,22 @@ const { NO: NO_MAPPER, MAPSTRUCT } = MapperTypes; const { CommonDBTypes, RelationalOnlyDBTypes, BlobTypes } = fieldTypes; -const { BIG_DECIMAL, BOOLEAN, DOUBLE, DURATION, ENUM, FLOAT, INTEGER, INSTANT, LOCAL_DATE, LONG, STRING, UUID, ZONED_DATE_TIME } = - CommonDBTypes; +const { + BIG_DECIMAL, + BOOLEAN, + DOUBLE, + DURATION, + ENUM, + FLOAT, + INTEGER, + INSTANT, + LOCAL_DATE, + LONG, + STRING, + UUID, + ZONED_DATE_TIME, + LOCAL_TIME, +} = CommonDBTypes; const { BYTES, BYTE_BUFFER } = RelationalOnlyDBTypes; const { ANY, IMAGE, TEXT } = BlobTypes; @@ -485,7 +499,7 @@ async function askForField(this: EntityGenerator) { { value: BOOLEAN, name: 'Boolean' }, { value: ENUM, name: 'Enumeration (Java enum type)' }, { value: UUID, name: 'UUID' }, - { value: UUID, name: 'UUID' }, + { value: LOCAL_TIME, name: 'LocalTime' }, ...(databaseType === CASSANDRA ? [{ value: BYTE_BUFFER, name: '[BETA] Blob' }] : [{ value: BYTES, name: '[BETA] Blob' }]), ], default: 0, diff --git a/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs b/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs index dd91a88ba956..e99b3e2edd5a 100644 --- a/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs +++ b/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs @@ -67,6 +67,8 @@ import java.time.Instant; import java.time.LocalDate; <%_ } if (anyFieldIsZonedDateTime) { _%> import java.time.ZonedDateTime; +<%_ } if (anyFieldIsLocalTime) { _%> +import java.time.LocalTime; <%_ } if (anyFieldIsDuration) { _%> import java.time.Duration; <%_ } if (entityContainsCollectionField) { _%> diff --git a/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap b/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap index 5e336e7d6676..4fd2fe4bf527 100644 --- a/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap +++ b/generators/liquibase/__snapshots__/incremental-liquibase.spec.ts.snap @@ -198,6 +198,7 @@ ROLE_USER + @@ -324,6 +325,7 @@ ROLE_USER + @@ -490,6 +492,7 @@ ROLE_USER + @@ -653,6 +656,7 @@ ROLE_USER + @@ -924,6 +928,7 @@ ROLE_USER + @@ -1238,6 +1243,7 @@ f4d7cebb-36aa-4812-9c05-b9abb67ab7ee;false;3133;2019-12-31T18:41:05 + @@ -1413,6 +1419,7 @@ ROLE_USER + @@ -2300,6 +2307,7 @@ abf7d979-e671-4258-8548-f4e98d56ee9c + @@ -2617,6 +2625,7 @@ ROLE_USER + @@ -2698,6 +2707,7 @@ ROLE_USER + @@ -2772,6 +2782,7 @@ ROLE_USER + @@ -2847,6 +2858,7 @@ ROLE_USER + diff --git a/generators/liquibase/support/prepare-field.ts b/generators/liquibase/support/prepare-field.ts index d0307c9f89fb..fdd2700ce4d1 100644 --- a/generators/liquibase/support/prepare-field.ts +++ b/generators/liquibase/support/prepare-field.ts @@ -25,7 +25,8 @@ import type { ApplicationType } from '../../../lib/types/application/application const { MYSQL, MARIADB } = databaseTypes; const { CommonDBTypes, RelationalOnlyDBTypes, BlobTypes } = fieldTypes; -const { STRING, INTEGER, LONG, BIG_DECIMAL, FLOAT, DOUBLE, UUID, BOOLEAN, LOCAL_DATE, ZONED_DATE_TIME, INSTANT, DURATION } = CommonDBTypes; +const { STRING, INTEGER, LONG, BIG_DECIMAL, FLOAT, DOUBLE, UUID, BOOLEAN, LOCAL_DATE, ZONED_DATE_TIME, INSTANT, DURATION, LOCAL_TIME } = + CommonDBTypes; const { BYTES } = RelationalOnlyDBTypes; const { TEXT } = BlobTypes; @@ -74,6 +75,11 @@ function parseLiquibaseColumnType(field: Field) { return 'bigint'; } + if (fieldType === LOCAL_TIME) { + // eslint-disable-next-line no-template-curly-in-string + return '${timeType}'; + } + if (fieldType === UUID) { // eslint-disable-next-line no-template-curly-in-string return '${uuidType}'; @@ -112,6 +118,11 @@ function parseLiquibaseLoadColumnType(application: ApplicationType, field: Field return 'date'; } + // eslint-disable-next-line no-template-curly-in-string + if (columnType === '${timeType}') { + return 'time'; + } + if (columnType === 'boolean') { return columnType; } diff --git a/generators/liquibase/templates/src/main/resources/config/liquibase/master.xml.ejs b/generators/liquibase/templates/src/main/resources/config/liquibase/master.xml.ejs index e9be8cf68ced..1ec16690f716 100644 --- a/generators/liquibase/templates/src/main/resources/config/liquibase/master.xml.ejs +++ b/generators/liquibase/templates/src/main/resources/config/liquibase/master.xml.ejs @@ -12,6 +12,7 @@ <%_ } _%> + <%_ if (prodDatabaseTypePostgresql) { _%> <%_ } else { _%> @@ -26,6 +27,7 @@ + <%_ } _%> <%_ if (prodDatabaseTypeMariadb) { _%> @@ -34,6 +36,7 @@ + <%_ } _%> <%_ if (prodDatabaseTypePostgresql) { _%> @@ -50,6 +53,7 @@ <%_ } _%> + <%_ } _%> <%_ if (prodDatabaseTypeOracle) { _%> @@ -58,6 +62,7 @@ + <%_ } _%> <%_ if (prodDatabaseTypeMssql) { _%> @@ -66,6 +71,7 @@ + <%_ } _%> <%_ if (databaseTypeNeo4j) { _%> @@ -74,6 +80,7 @@ + <%_ } _%> diff --git a/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs b/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs index af6bfc9cf988..1ad0119ace0b 100644 --- a/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs +++ b/generators/react/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.tsx.ejs @@ -250,6 +250,11 @@ _%> type="date" <%- include('react_validators'); %> /> + <%_ } else if (field.fieldTypeLocalTime) { _%> + type="time" + placeholder="HH:mm" + <%- include('react_validators'); %> + /> <%_ } else if (field.fieldIsEnum) {_%> type="select" > diff --git a/generators/server/support/build-specification-mapper.ts b/generators/server/support/build-specification-mapper.ts index 269a9a94ae16..baded7214986 100644 --- a/generators/server/support/build-specification-mapper.ts +++ b/generators/server/support/build-specification-mapper.ts @@ -12,6 +12,7 @@ const { ZONED_DATE_TIME: TYPE_ZONED_DATE_TIME, INSTANT: TYPE_INSTANT, DURATION: TYPE_DURATION, + LOCAL_TIME: TYPE_LOCAL_TIME, } = fieldTypes.CommonDBTypes; /** @@ -30,6 +31,7 @@ export const getSpecificationBuildForType = (fieldType: FieldType) => { TYPE_ZONED_DATE_TIME, TYPE_INSTANT, TYPE_DURATION, + TYPE_LOCAL_TIME, ].includes(fieldType) ) { return 'buildRangeSpecification'; diff --git a/generators/spring-boot/generator.ts b/generators/spring-boot/generator.ts index 8ffe091f742a..bab435c6f208 100644 --- a/generators/spring-boot/generator.ts +++ b/generators/spring-boot/generator.ts @@ -382,6 +382,10 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) { field.fieldTypeBoolean ) { field.propertyJavaFilterType = `${fieldType}Filter`; + } else if (field.fieldTypeLocalTime) { + const filterType = `${fieldType}Filter`; + field.propertyJavaFilterType = filterType; + field.propertyJavaCustomFilter = { type: filterType, superType: `RangeFilter<${fieldType}>`, fieldType }; } else { field.propertyJavaFilterType = `Filter<${fieldType}>`; } diff --git a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/criteria/_entityClass_Criteria.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/criteria/_entityClass_Criteria.java.ejs index e864ee46380a..2a8e135c48df 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/criteria/_entityClass_Criteria.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/criteria/_entityClass_Criteria.java.ejs @@ -7,9 +7,14 @@ import java.util.function.BiFunction; import org.springdoc.core.annotations.ParameterObject; import tech.jhipster.service.Criteria; -<%_ for (const field of fields) { if (field.fieldIsEnum === true) { _%> +<%_ for (const field of fields) { _%> + <%_ if (field.fieldIsEnum === true) { _%> import <%- entityAbsolutePackage %>.domain.enumeration.<%- field.fieldType %>; -<%_ } } _%> + <%_ } _%> +<%_ } _%> +<%_ if (anyFieldIsLocalTime) { _%> +import java.time.LocalTime; +<%_ } _%> import tech.jhipster.service.filter.*; /** diff --git a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs index ae32e61fcabb..f38c320f2bd5 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/_entityPackage_/service/dto/_dtoClass_.java.ejs @@ -28,6 +28,9 @@ import java.time.Instant; <%_ if (anyFieldIsLocalDate) { _%> import java.time.LocalDate; <%_ } _%> +<%_ if (anyFieldIsLocalTime) { _%> +import java.time.LocalTime; +<%_ } _%> <%_ if (anyFieldIsZonedDateTime) { _%> import java.time.ZonedDateTime; <%_ } _%> diff --git a/generators/spring-boot/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs index 21484780278d..5549b0a71cdc 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/config/JacksonConfiguration.java.ejs @@ -22,9 +22,15 @@ package <%= packageName %>.config; import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module; import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module.Feature; <%_ } _%> +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; +import java.time.LocalTime; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -37,7 +43,14 @@ public class JacksonConfiguration { */ @Bean public JavaTimeModule javaTimeModule() { - return new JavaTimeModule(); + final JavaTimeModule javaTime = new JavaTimeModule(); + javaTime.addSerializer(LocalTime.class, new JsonSerializer() { + @Override + public void serialize(LocalTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(value.toString()); + } + }); + return javaTime; } @Bean diff --git a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs index 7992d1cb8fba..5ef1a7cd5353 100644 --- a/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs +++ b/generators/spring-boot/templates/src/test/java/_package_/_entityPackage_/web/rest/_entityClass_ResourceIT.java.ejs @@ -192,6 +192,9 @@ import java.time.ZoneId; <%_ if (anyFieldIsInstant) { _%> import java.time.temporal.ChronoUnit; <%_ } _%> +<%_ if (anyFieldIsLocalTime) { _%> +import java.time.LocalTime; +<%_ } _%> <%_ if (!reactive && implementsEagerLoadApis) { _%> import java.util.ArrayList; <%_ } _%> @@ -413,6 +416,13 @@ if (field.fieldTypeString || field.blobContentTypeText) { <%_ if (needsSmallerValueName) { _%> private static final ZonedDateTime <%= smallerValueName %> = ZonedDateTime.ofInstant(Instant.ofEpochMilli(-1L), ZoneOffset.UTC); <%_ } _%> + <%_ } else if (field.fieldTypeLocalTime) { _%> + + private static final LocalTime <%= defaultValueName %> = LocalTime.NOON; + private static final LocalTime <%= updatedValueName %> = LocalTime.MAX.withNano(0); + <%_ if (needsSmallerValueName) { _%> + private static final LocalTime <%= smallerValueName %> = LocalTime.MIN; + <%_ } _%> <%_ } else if (field.fieldTypeDuration) { _%> private static final Duration <%= defaultValueName %> = Duration.ofHours(6); diff --git a/generators/spring-data-cassandra/templates/src/main/resources/config/cql/changelog/added_entity.cql.ejs b/generators/spring-data-cassandra/templates/src/main/resources/config/cql/changelog/added_entity.cql.ejs index 1c1425b88a23..658ffc53ac71 100644 --- a/generators/spring-data-cassandra/templates/src/main/resources/config/cql/changelog/added_entity.cql.ejs +++ b/generators/spring-data-cassandra/templates/src/main/resources/config/cql/changelog/added_entity.cql.ejs @@ -43,6 +43,8 @@ CREATE TABLE IF NOT EXISTS <%= entityInstance %> ( <%= fieldName %> text, <%_ } else if (field.fieldTypeZonedDateTime) { _%> <%= fieldName %> tuple, + <%_ } else if (field.fieldTypeLocalTime) { _%> + <%= fieldName %> time, <%_ } else if (field.fieldTypeBoolean) { _%> <%= fieldName %> boolean, <%_ } else if (field.fieldTypeByteBuffer) { _%> diff --git a/generators/spring-data-elasticsearch/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.elastic_search.ejs b/generators/spring-data-elasticsearch/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.elastic_search.ejs index b33d63183f04..ff48c34e1df6 100644 --- a/generators/spring-data-elasticsearch/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.elastic_search.ejs +++ b/generators/spring-data-elasticsearch/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.elastic_search.ejs @@ -38,6 +38,8 @@ @org.springframework.data.elasticsearch.annotations.Field(type = org.springframework.data.elasticsearch.annotations.FieldType.Boolean) <%_ } else if (field.fieldTypeInteger) { _%> @org.springframework.data.elasticsearch.annotations.Field(type = org.springframework.data.elasticsearch.annotations.FieldType.Integer) + <%_ } else if (field.fieldTypeLocalTime) { _%> + @org.springframework.data.elasticsearch.annotations.Field(type = org.springframework.data.elasticsearch.annotations.FieldType.Date, format = org.springframework.data.elasticsearch.annotations.DateFormat.hour_minute_second_millis) <%_ } _%> <%_ } _%> <&_ } -&> diff --git a/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/repository/rowmapper/_entityClass_RowMapper_reactive.java.ejs b/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/repository/rowmapper/_entityClass_RowMapper_reactive.java.ejs index cde093b0f8ee..217b3e3ea9c1 100644 --- a/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/repository/rowmapper/_entityClass_RowMapper_reactive.java.ejs +++ b/generators/spring-data-relational/templates/src/main/java/_package_/_entityPackage_/repository/rowmapper/_entityClass_RowMapper_reactive.java.ejs @@ -26,6 +26,8 @@ import java.time.Instant; import java.time.LocalDate; <%_ } if (anyFieldIsZonedDateTime) { _%> import java.time.ZonedDateTime; +<%_ } if (anyFieldIsLocalTime) { _%> +import java.time.LocalTime; <%_ } if (anyFieldIsDuration) { _%> import java.time.Duration; <%_ } if (anyFieldIsUUID || otherEntityPrimaryKeyTypesIncludesUUID) { _%> diff --git a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.vue.ejs b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.vue.ejs index ea434b06b591..ee30c37b6106 100644 --- a/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.vue.ejs +++ b/generators/vue/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_-update.vue.ejs @@ -23,6 +23,8 @@ fieldInputType = 'date'; } else if (field.fieldTypeTimed) { fieldInputType = 'datetime-local'; + } else if (field.fieldTypeLocalTime) { + fieldInputType = 'time'; } else if (field.fieldTypeBoolean) { fieldInputType = 'checkbox'; fieldInputClass = 'form-check'; diff --git a/lib/application/field-types.ts b/lib/application/field-types.ts index 8df39dcf8f27..6c983002485d 100644 --- a/lib/application/field-types.ts +++ b/lib/application/field-types.ts @@ -25,6 +25,7 @@ const fieldTypes = { ZONED_DATE_TIME: 'ZonedDateTime', INSTANT: 'Instant', DURATION: 'Duration', + TIME: 'LocalTime', BYTES: 'byte[]', // Supported by mongodb at CI samples BYTE_BUFFER: 'ByteBuffer', ...blobFieldTypes, diff --git a/lib/jhipster/field-types.ts b/lib/jhipster/field-types.ts index bd90862063ab..fd68a7cd7bd2 100644 --- a/lib/jhipster/field-types.ts +++ b/lib/jhipster/field-types.ts @@ -47,6 +47,7 @@ export const CommonDBTypes = { DURATION: 'Duration', BYTES: 'byte[]', // Supported by mongodb at CI samples BYTE_BUFFER: 'ByteBuffer', // Supported by cassandra at CI samples + LOCAL_TIME: 'LocalTime', }; export const RelationalOnlyDBTypes = { @@ -78,6 +79,7 @@ const CommonDBValidations = { UUID: new Set([REQUIRED, UNIQUE]), Instant: new Set([REQUIRED, UNIQUE]), Duration: new Set([REQUIRED, UNIQUE]), + LocalTime: new Set([REQUIRED, UNIQUE]), }; export default { diff --git a/lib/types/application/entity.d.ts b/lib/types/application/entity.d.ts index 73a1788f56a7..278a97a86beb 100644 --- a/lib/types/application/entity.d.ts +++ b/lib/types/application/entity.d.ts @@ -129,6 +129,7 @@ export interface Entity