Compare commits

...

13 Commits

Author SHA1 Message Date
8dde49adff [FIX] ApiNotNull inplementation 2025-04-03 10:25:33 +02:00
5960bbc666 [VERSION] update dev tag version 2025-04-02 23:50:03 +02:00
afcbb4711c [RELEASE] Release v0.26.2 2025-04-02 23:50:00 +02:00
a0b22e00bd [FEAT] update for maven central 2025-04-02 23:49:28 +02:00
a49e374bd1 [DEV] remove unneeded libraries 2025-04-02 22:28:23 +02:00
2b43d348a8 [VERSION] update dev tag version 2025-04-02 21:46:56 +02:00
242e6b9261 [RELEASE] Release v0.26.0 2025-04-02 21:46:53 +02:00
c627484b49 [FIX] annotation in the common model 2025-04-02 21:42:17 +02:00
44df939873 [FEAT] add ApiNotNull to overwrite all fields possibility 2025-04-02 21:34:27 +02:00
b283f8545c [FEAT] add readable optionnal for field 2025-04-02 21:33:52 +02:00
dependabot[bot]
6e4c10724a [DEV-OPS] (dependabot) Bump org.apache.maven.plugins:maven-surefire-plugin
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.2...surefire-3.5.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-02 19:39:12 +02:00
41aa78667f [FIX] some basic types generation constraint 2025-04-01 22:18:58 +02:00
f7ba570913 [FIX] foreinKeyValidator 2025-04-01 22:18:50 +02:00
17 changed files with 165 additions and 73 deletions

80
pom.xml
View File

@ -1,24 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<groupId>org.atria-soft</groupId>
<artifactId>archidata</artifactId>
<version>0.25.7-SNAPSHOT</version>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<version>0.26.3-SNAPSHOT</version>
<licenses>
<license>
<name>Mozilla Public License 2.0</name>
<url>https://opensource.org/licenses/MPL-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>dev1</id>
<name>Edouard DUPIN</name>
<email>yui.heero@gmail.com</email>
<roles>
<role>Lead Developer</role>
</roles>
</developer>
</developers>
<scm>
<url>https://github.com/kangaroo-and-rabbit/archidata</url>
<connection>scm:git:git://github.com/kangaroo-and-rabbit/archidata.git</connection>
<developerConnection>scm:git:ssh:github.com/kangaroo-and-rabbit/archidata.git</developerConnection>
</scm>
<distributionManagement>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
<snapshotRepository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</snapshotRepository>
</distributionManagement>
<dependencyManagement>
<dependencies>
@ -89,16 +101,6 @@
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.4.0-b180830.0359</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
@ -109,17 +111,6 @@
<artifactId>jakarta.ws.rs-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.istack</groupId>
<artifactId>istack-commons-runtime</artifactId>
<version>4.2.0</version>
</dependency>
<!-- continu to be needed ??? -->
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<scope>test</scope>
</dependency>
<!-- Serialize and un-serialize request in JSON-->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
@ -202,11 +193,6 @@
<artifactId>hibernate-validator</artifactId>
<version>9.0.0.CR1</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!--
************************************************************
** TEST dependency **
@ -290,7 +276,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<version>3.5.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
@ -372,6 +358,18 @@
-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->

View File

@ -9,6 +9,11 @@ import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(FIELD)
public @interface ApiAccessLimitation {
/**
* (Optional) The field is accessible in read (GET)
*/
boolean readable() default true;
/**
* (Optional) The field is accessible in creation (POST)
*/

View File

@ -0,0 +1,45 @@
package org.kar.archidata.annotation.apiGenerator;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to explicitly define the nullability of a parameter in an API.
*
* This annotation allows marking a parameter as required (non-null) or optional (nullable),
* overriding any other nullability considerations. It is useful in API generation frameworks
* to ensure precise validation and documentation of method parameters.
*
* <p>Usage:
* - Target: This annotation can be applied to field.
* - Retention: The annotation is retained at runtime, allowing it to be
* processed by frameworks or libraries that handle code generation logic.
*
* <p>Behavior:
* - When applied to a parameter, it explicitly marks it as optional or required in the API.
* This annotation overrides all other considerations regarding nullability.
*
* <p>Example:
* <pre>{@code
* public class User {
* @ReadOnlyField
* @ApiNotNull
* public String username;
* public String email;
* }
* }</pre>
*
* In this example, the `username` field in the `User` class is explicitly marked as non-null in the generated API.
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiNotNull {
/**
* (Optional) Specifies whether the API element can be null.
* If set to `true`, the element is required (non-null).
* If set to `false`, the element is optional (nullable).
*/
boolean value() default true;
}

View File

@ -9,7 +9,15 @@ import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Constraint(validatedBy = CheckForeignKeyValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Target({ ElementType.TYPE, //
ElementType.METHOD, //
ElementType.FIELD, //
ElementType.ANNOTATION_TYPE, //
ElementType.CONSTRUCTOR, //
ElementType.PARAMETER, //
ElementType.TYPE_USE, //
})
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckForeignKey {
Class<?> target();

View File

@ -1,14 +1,15 @@
package org.kar.archidata.annotation.checker;
import java.util.Collection;
import org.kar.archidata.dataAccess.DataAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CheckForeignKeyValidator implements ConstraintValidator<CheckForeignKey, Object> {
Class<?> target = null;
private final static Logger LOGGER = LoggerFactory.getLogger(CheckForeignKeyValidator.class);
@Override
public void initialize(final CheckForeignKey annotation) {
@ -17,26 +18,18 @@ public class CheckForeignKeyValidator implements ConstraintValidator<CheckForeig
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
if (value != null) {
if (value == null) {
return true;
}
if (value instanceof final Collection<?> tmpCollection) {
final Object[] elements = tmpCollection.toArray();
for (final Object element : elements) {
if (element == null) {
continue;
}
try {
final long count = DataAccess.count(this.target, element);
if (count != 1) {
return false;
}
} catch (final Exception e) {
// TODO ...
return false;
}
try {
final long count = DataAccess.count(this.target, value);
if (count != 1) {
return false;
}
} catch (final Exception e) {
LOGGER.error("Fail to access to the DB");
context.buildConstraintViolationWithTemplate("fail to access on the DB").addConstraintViolation();
return false;
}
return true;
}

View File

@ -13,6 +13,7 @@ import java.util.Set;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.apiGenerator.ApiNotNull;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.AnnotationCreator;
import org.slf4j.Logger;
@ -83,13 +84,26 @@ public class ClassObjectModel extends ClassModel {
Email email,
ApiAccessLimitation accessLimitation,
Boolean notNull,
ApiNotNull apiNotNull,
Boolean columnNotNull,
Boolean nullable) {
public FieldProperty(final String name, final ClassModel model, final ClassModel linkClass,
final String comment, final Size stringSize, final Min min, final Max max, final DecimalMin decimalMin,
final DecimalMax decimalMax, final Pattern pattern, final Email email,
final ApiAccessLimitation accessLimitation, final Boolean notNull, final Boolean columnNotNull,
public FieldProperty(//
final String name, //
final ClassModel model, //
final ClassModel linkClass, //
final String comment, //
final Size stringSize, //
final Min min, //
final Max max, //
final DecimalMin decimalMin, //
final DecimalMax decimalMax, //
final Pattern pattern, //
final Email email, //
final ApiAccessLimitation accessLimitation, //
final Boolean notNull, //
final ApiNotNull apiNotNull, //
final Boolean columnNotNull, //
final Boolean nullable) {
this.name = name;
this.model = model;
@ -108,6 +122,7 @@ public class ClassObjectModel extends ClassModel {
this.accessLimitation = accessLimitation;
}
this.notNull = notNull;
this.apiNotNull = apiNotNull;
this.columnNotNull = columnNotNull;
this.nullable = nullable;
@ -160,6 +175,7 @@ public class ClassObjectModel extends ClassModel {
AnnotationTools.getConstraintsEmail(field), //
AnnotationTools.get(field, ApiAccessLimitation.class), //
AnnotationTools.getConstraintsNotNull(field), //
AnnotationTools.get(field, ApiNotNull.class), //
AnnotationTools.getColumnNotNull(field), //
AnnotationTools.getNullable(field));
}

View File

@ -237,6 +237,9 @@ public class TsClassElement {
}
public boolean isOptionalTypeZod(final FieldProperty field) {
if (field.apiNotNull() != null) {
return !field.apiNotNull().value();
}
// Common checking element (apply to List, Map, ...)
if (field.nullable()) {
return true;
@ -287,13 +290,13 @@ public class TsClassElement {
builder.append(")");
}
}
/*Must be tested before
/* Must be tested before
if (field.pattern() != null) {
builder.append(".regex((");
builder.append(field.pattern().regexp());
builder.append(")");
}*/
/*Must be tested before
/* Must be tested before
if (field.email() != null) {
builder.append(".regex((");
builder.append(field.email().regexp());
@ -396,6 +399,10 @@ public class TsClassElement {
out.append("zod.object({\n");
}
for (final FieldProperty field : model.getFields()) {
// remove all readOnly field
if (!field.accessLimitation().readable()) {
continue;
}
final ClassModel fieldModel = field.model();
if (field.comment() != null) {
out.append("\t/**\n");

View File

@ -2,6 +2,8 @@ package org.kar.archidata.model;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.apiGenerator.ApiNotNull;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
@ -15,6 +17,8 @@ public class GenericData extends GenericTiming {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, unique = true)
@Schema(description = "Unique Id of the object", example = "123456")
@ReadOnlyField
@ApiNotNull
@ApiAccessLimitation(creatable = false, updatable = false)
public Long id = null;
}

View File

@ -4,6 +4,7 @@ import org.kar.archidata.annotation.DataDeleted;
import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
@ -18,6 +19,7 @@ public class GenericDataSoftDelete extends GenericData {
@DataDeleted
@Schema(description = "Deleted state", hidden = true)
@Nullable
@ReadOnlyField
@ApiAccessLimitation(creatable = false, updatable = false)
public Boolean deleted = null;
}

View File

@ -7,6 +7,7 @@ import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import com.fasterxml.jackson.annotation.JsonFormat;
@ -22,6 +23,7 @@ public class GenericTiming {
@Schema(description = "Create time of the object", example = "2000-01-23T01:23:45.678+01:00")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
@Nullable
@ReadOnlyField
@ApiAccessLimitation(creatable = false, updatable = false)
public Date createdAt = null;
@DataNotRead
@ -30,6 +32,7 @@ public class GenericTiming {
@Schema(description = "When update the object", example = "2000-01-23T00:23:45.678Z")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
@Nullable
@ReadOnlyField
@ApiAccessLimitation(creatable = false, updatable = false)
public Date updatedAt = null;
}

View File

@ -3,11 +3,12 @@ package org.kar.archidata.model;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.apiGenerator.ApiNotNull;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import dev.morphia.annotations.Id;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
@ApiGenerationMode(create = true, update = true)
public class OIDGenericData extends GenericTiming {
@ -15,7 +16,8 @@ public class OIDGenericData extends GenericTiming {
@jakarta.persistence.Id
@Column(nullable = false, unique = true, name = "_id")
@Schema(description = "Unique ObjectID of the object", example = "65161616841351")
@NotNull
@ReadOnlyField
@ApiNotNull
@ApiAccessLimitation(creatable = false, updatable = false)
public ObjectId oid = null;
}

View File

@ -4,6 +4,7 @@ import org.kar.archidata.annotation.DataDeleted;
import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
@ -18,6 +19,7 @@ public class OIDGenericDataSoftDelete extends OIDGenericData {
@DataDeleted
@Schema(description = "Deleted state", hidden = true)
@Nullable
@ReadOnlyField
@ApiAccessLimitation(creatable = false, updatable = false)
public Boolean deleted = null;
}

View File

@ -4,11 +4,12 @@ import java.util.UUID;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.apiGenerator.ApiNotNull;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.DefaultValue;
@ApiGenerationMode(create = true, update = true)
@ -17,7 +18,8 @@ public class UUIDGenericData extends GenericTiming {
@DefaultValue("(UUID_TO_BIN(UUID(), TRUE))")
@Column(nullable = false, unique = true)
@Schema(description = "Unique UUID of the object", example = "e6b33c1c-d24d-11ee-b616-02420a030102")
@NotNull
@ReadOnlyField
@ApiNotNull
@ApiAccessLimitation(creatable = false, updatable = false)
public UUID uuid = null;
}

View File

@ -4,6 +4,7 @@ import org.kar.archidata.annotation.DataDeleted;
import org.kar.archidata.annotation.DataNotRead;
import org.kar.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
@ -18,6 +19,7 @@ public class UUIDGenericDataSoftDelete extends UUIDGenericData {
@DataDeleted
@Schema(description = "Deleted state", hidden = true)
@Nullable
@ReadOnlyField
@ApiAccessLimitation(creatable = false, updatable = false)
public Boolean deleted = null;
}

View File

@ -16,7 +16,7 @@ public class JwtPayload {
public String iss;
// Access Right Map<application, Map< section, right>>
@NotNull
public Map<String, Map<String, Long>> right;
public Map<@NotNull String, Map<@NotNull String, @NotNull Long>> right;
// user name
@NotNull
public String login;

View File

@ -1,11 +1,14 @@
package org.kar.archidata.model.token;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
public class JwtToken {
@NotNull
@Valid
public JwtHeader header;
@NotNull
@Valid
public JwtPayload payload;
@NotNull
public String signature;

View File

@ -1 +1 @@
0.25.7-dev
0.26.3-dev