[DEV] integrate hybernate validator

This commit is contained in:
Edouard DUPIN 2025-03-16 10:53:59 +01:00
parent a4521853c3
commit 1281415c48
23 changed files with 661 additions and 13 deletions

View File

@ -85,6 +85,10 @@
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
@ -246,7 +250,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>4.0.0-beta-2</version>
<version>3.14.0</version>
<configuration>
<source>21</source>
<target>21</target>

View File

@ -5,8 +5,18 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Constraint(validatedBy = CheckForeignKeyValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckForeignKey {
Class<?> target();
String message() default "Foreign-key does not exist in the DB";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,43 @@
package org.kar.archidata.annotation.checker;
import java.util.Collection;
import org.kar.archidata.dataAccess.DataAccess;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CheckForeignKeyValidator implements ConstraintValidator<CheckForeignKey, Object> {
Class<?> target = null;
@Override
public void initialize(final CheckForeignKey annotation) {
this.target = annotation.target();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
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;
}
}
}
return true;
}
}

View File

@ -5,8 +5,16 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Constraint(validatedBy = CollectionItemNotNullValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CollectionItemNotNull {
String message() default "Collection can not contain NULL item";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,31 @@
package org.kar.archidata.annotation.checker;
import java.util.Collection;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CollectionItemNotNullValidator implements ConstraintValidator<CollectionItemNotNull, Object> {
@Override
public void initialize(final CollectionItemNotNull annotation) {
// nothing to do...
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
if (value == null) {
return true;
}
if (value instanceof final Collection<?> tmpCollection) {
final Object[] elements = tmpCollection.toArray();
for (final Object element : elements) {
if (element == null) {
return false;
//throw new InputException(baseName + fieldName + '[' + iii + ']', "Collection can not contain NULL item");
}
}
}
return true;
}
}

View File

@ -5,8 +5,17 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Constraint(validatedBy = CollectionItemUniqueValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CollectionItemUnique {
String message() default "Cannot insert multiple times the same elements";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,30 @@
package org.kar.archidata.annotation.checker;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CollectionItemUniqueValidator implements ConstraintValidator<CollectionItemUnique, Object> {
@Override
public void initialize(final CollectionItemUnique annotation) {
// nothing to do...
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
if (value == null) {
return true;
}
if (value instanceof final Collection<?> tmpCollection) {
final Set<Object> uniqueValues = new HashSet<>(tmpCollection);
if (uniqueValues.size() != tmpCollection.size()) {
return false;
}
}
return true;
}
}

View File

@ -5,8 +5,17 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Constraint(validatedBy = CollectionNotEmptyValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CollectionNotEmpty {
String message() default "Collection can not be empty";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,27 @@
package org.kar.archidata.annotation.checker;
import java.util.Collection;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CollectionNotEmptyValidator implements ConstraintValidator<CollectionNotEmpty, Object> {
@Override
public void initialize(final CollectionNotEmpty annotation) {
// nothing to do...
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
if (value == null) {
return true;
}
if (value instanceof final Collection<?> tmpCollection) {
if (tmpCollection.isEmpty()) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,20 @@
package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Constraint(validatedBy = ReadOnlyFieldValidator.class)
@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyField {
String message() default "Field can not be set, it is a read-only field.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,20 @@
package org.kar.archidata.annotation.checker;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class ReadOnlyFieldValidator implements ConstraintValidator<ReadOnlyField, Object> {
@Override
public void initialize(final ReadOnlyField annotation) {
// nothing to do...
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
if (value != null) {
return false;
}
return true;
}
}

View File

@ -1,5 +1,11 @@
package org.kar.archidata.catcher;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -20,7 +26,22 @@ public class ConstraintViolationExceptionCatcher implements ExceptionMapper<Cons
}
private RestErrorResponse build(final ConstraintViolationException exception) {
return new RestErrorResponse(Response.Status.BAD_REQUEST, "Constraint Violation", exception.getMessage());
final List<RestInputError> inputError = new ArrayList<>();
for (final var cv : exception.getConstraintViolations()) {
if (cv == null) {
continue;
}
inputError.add(new RestInputError(cv.getPropertyPath(), cv.getMessage()));
}
Collections.sort(inputError, Comparator.comparing(RestInputError::getFullPath));
String errorType = "Multiple error on input";
if (inputError.size() == 0) {
errorType = "Constraint Violation";
} else if (inputError.size() == 1) {
errorType = "Error on input='" + inputError.get(0).path + "'";
}
return new RestErrorResponse(Response.Status.BAD_REQUEST, Instant.now().toString(), errorType,
exception.getMessage(), inputError);
}
}

View File

@ -1,6 +1,7 @@
package org.kar.archidata.catcher;
import java.time.Instant;
import java.util.List;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
@ -27,6 +28,18 @@ public class RestErrorResponse {
@Column(length = 0)
final public String statusMessage;
final public List<RestInputError> inputError;
public RestErrorResponse(final Response.Status status, final String time, final String error, final String message,
final List<RestInputError> inputError) {
this.time = time;
this.name = error;
this.message = message;
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
this.inputError = inputError;
}
public RestErrorResponse(final Response.Status status, final String time, final String error,
final String message) {
this.time = time;
@ -34,6 +47,7 @@ public class RestErrorResponse {
this.message = message;
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
this.inputError = null;
}
public RestErrorResponse(final Response.Status status, final String error, final String message) {
@ -42,6 +56,7 @@ public class RestErrorResponse {
this.message = message;
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
this.inputError = null;
}
public RestErrorResponse(final Response.Status status) {
@ -50,6 +65,7 @@ public class RestErrorResponse {
this.time = Instant.now().toString();
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
this.inputError = null;
}
}

View File

@ -0,0 +1,50 @@
package org.kar.archidata.catcher;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jakarta.persistence.Column;
import jakarta.validation.Path;
import jakarta.validation.constraints.NotNull;
public class RestInputError {
private static Pattern PATTERN = Pattern.compile("^([^.]+)\\.([^.]+)(\\.(.*))?");
@Column(length = 0)
public String argument;
@Column(length = 0)
public String path;
@NotNull
@Column(length = 0)
public String message;
@Override
public String toString() {
return "RestInputError [argument=" + this.argument + ", path=" + this.path + ", message=" + this.message + "]";
}
public RestInputError() {}
public RestInputError(final Path path, final String message) {
final Matcher matcher = PATTERN.matcher(path.toString());
if (matcher.find()) {
//String firstPart = matcher.group(1); this is the request base element ==> not needed
this.argument = matcher.group(2);
this.path = matcher.group(4);
} else {
this.path = path.toString();
}
this.message = message;
}
public RestInputError(final String path, final String message) {
this.path = path;
this.message = message;
}
String getFullPath() {
if (this.path == null) {
return this.argument;
}
return this.argument + "." + this.path;
}
}

View File

@ -1,6 +1,9 @@
package org.kar.archidata.exception;
import java.util.List;
import org.bson.types.ObjectId;
import org.kar.archidata.catcher.RestInputError;
public class RESTErrorResponseException extends Exception {
private static final long serialVersionUID = 1L;
@ -10,6 +13,7 @@ public class RESTErrorResponseException extends Exception {
public String message;
public int status;
public String statusMessage;
public List<RestInputError> inputError;
public RESTErrorResponseException() {
this.oid = new ObjectId();
@ -18,16 +22,18 @@ public class RESTErrorResponseException extends Exception {
this.message = null;
this.status = 0;
this.statusMessage = null;
this.inputError = null;
}
public RESTErrorResponseException(final ObjectId oid, final String time, final String name, final String message,
final int status, final String statusMessage) {
final int status, final String statusMessage, final List<RestInputError> inputError) {
this.oid = oid;
this.time = time;
this.name = name;
this.message = message;
this.status = status;
this.statusMessage = statusMessage;
this.inputError = inputError;
}
@Override

View File

@ -17,6 +17,7 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import jakarta.ws.rs.core.HttpHeaders;
@ -170,14 +171,21 @@ public class RESTApi {
final RESTErrorResponseException out = this.mapper.readValue(httpResponse.body(),
RESTErrorResponseException.class);
throw out;
} catch (final InvalidDefinitionException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
} catch (final MismatchedInputException ex) {
throw new IOException(
"Fail to get the data [" + httpResponse.statusCode() + "] " + httpResponse.body());
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
} catch (final JsonParseException ex) {
ex.printStackTrace();
LOGGER.error("body: {}", httpResponse.body());
throw new IOException(
"Fail to get the ERROR data [" + httpResponse.statusCode() + "] " + httpResponse.body());
throw new IOException("RestAPI Fail to parse the error " + ex.getClass().getName() + " ["
+ httpResponse.statusCode() + "] " + httpResponse.body());
}
}
if (clazz == Void.class || clazz == void.class) {

View File

@ -30,8 +30,6 @@ public class TestTime {
static WebLauncherTest webInterface = null;
static RESTApi api = null;
private static Long idTest = 0L;
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();

View File

@ -0,0 +1,95 @@
package test.kar.archidata.hybernateValidator;
import java.util.ArrayList;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.exception.RESTErrorResponseException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test.kar.archidata.ConfigureDb;
import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.apiExtern.Common;
import test.kar.archidata.hybernateValidator.model.ValidatorModel;
import test.kar.archidata.hybernateValidator.model.ValidatorSubModel;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestValidator {
private final static Logger LOGGER = LoggerFactory.getLogger(TestValidator.class);
public final static String ENDPOINT_NAME = "TestResourceValidator";
static WebLauncherTest webInterface = null;
static RESTApi api = null;
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Clean previous table");
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
api.setToken(Common.ADMIN_TOKEN);
}
@AfterAll
public static void stopWebServer() throws Exception {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
ConfigureDb.clear();
}
@Order(2)
@Test
public void DetectGenericError() throws Exception {
final ValidatorModel data = new ValidatorModel();
data.value = "plop";
data.data = "klsdfsdfsdfsdfj";
data.multipleElement = new ArrayList<>();
ValidatorSubModel tmp = new ValidatorSubModel();
tmp.data = "lkmkmlkmlklm";
data.multipleElement.add(tmp);
tmp = new ValidatorSubModel();
tmp.data = "1";
data.multipleElement.add(tmp);
data.subElement = new ValidatorSubModel();
data.subElement.data = "k";
final RESTErrorResponseException exception = Assertions.assertThrows(RESTErrorResponseException.class,
() -> api.post(void.class, TestValidator.ENDPOINT_NAME + "?queryParametersName=2", data));
Assertions.assertNotNull(exception);
LOGGER.debug("error on input:{}", exception);
Assertions.assertNull(exception.getMessage());
Assertions.assertNotNull(exception.inputError);
Assertions.assertEquals(5, exception.inputError.size());
Assertions.assertEquals("arg0", exception.inputError.get(0).argument);
Assertions.assertEquals(null, exception.inputError.get(0).path);
Assertions.assertEquals("must be greater than or equal to 5", exception.inputError.get(0).message);
Assertions.assertEquals("arg1", exception.inputError.get(1).argument);
Assertions.assertEquals("data", exception.inputError.get(1).path);
Assertions.assertEquals("size must be between 0 and 5", exception.inputError.get(1).message);
Assertions.assertEquals("arg1", exception.inputError.get(2).argument);
Assertions.assertEquals("multipleElement[1].data", exception.inputError.get(2).path);
Assertions.assertEquals("size must be between 2 and 2147483647", exception.inputError.get(2).message);
Assertions.assertEquals("arg1", exception.inputError.get(3).argument);
Assertions.assertEquals("subElement.data", exception.inputError.get(3).path);
Assertions.assertEquals("size must be between 2 and 2147483647", exception.inputError.get(3).message);
Assertions.assertEquals("arg1", exception.inputError.get(4).argument);
Assertions.assertEquals("value", exception.inputError.get(4).path);
Assertions.assertEquals("Field can not be set, it is a read-only field.", exception.inputError.get(4).message);
}
}

View File

@ -0,0 +1,163 @@
package test.kar.archidata.hybernateValidator;
import java.net.URI;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.validation.ValidationFeature;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.catcher.GenericCatcher;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.UriBuilder;
import test.kar.archidata.hybernateValidator.resource.TestResourceValidator;
public class WebLauncher {
final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
protected UpdateJwtPublicKey keyUpdater = null;
protected HttpServer server = null;
public WebLauncher() {}
private static URI getBaseURI() {
return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build();
}
public void migrateDB() throws Exception {
WebLauncher.LOGGER.info("Create migration engine");
final MigrationEngine migrationEngine = new MigrationEngine();
WebLauncher.LOGGER.info("Add initialization");
//migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version");
//migrationEngine.add(new Migration20231126());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
}
public static void main(final String[] args) throws Exception {
WebLauncher.LOGGER.info("[START] application wake UP");
final WebLauncher launcher = new WebLauncher();
launcher.migrateDB();
launcher.process();
WebLauncher.LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
WebLauncher.LOGGER.info("STOP Key updater");
launcher.stopOther();
WebLauncher.LOGGER.info("STOP the REST server:");
}
public void plop(final String aaa) {
// List available Image Readers
WebLauncher.LOGGER.trace("Available Image Readers:");
final Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(aaa);
while (readers.hasNext()) {
final ImageReader reader = readers.next();
WebLauncher.LOGGER.trace("Reader: " + reader.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Reader CN: " + reader.getOriginatingProvider().getPluginClassName());
// ImageIO.deregisterServiceProvider(reader.getOriginatingProvider());
}
// List available Image Writers
WebLauncher.LOGGER.trace("\nAvailable Image Writers:");
final Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(aaa);
while (writers.hasNext()) {
final ImageWriter writer = writers.next();
WebLauncher.LOGGER.trace("Writer: " + writer.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Writer CN: " + writer.getOriginatingProvider().getPluginClassName());
}
}
public void process() throws InterruptedException, DataAccessException {
ImageIO.scanForPlugins();
plop("jpeg");
plop("png");
plop("webmp");
plop("webp");
// ===================================================================
// Configure resources
// ===================================================================
final ResourceConfig rc = new ResourceConfig();
// add multipart models ..
rc.register(MultiPartFeature.class);
// global authentication system
rc.register(OptionFilter.class);
// remove cors ==> all time called by an other system...
rc.register(CORSFilter.class);
// register exception catcher
GenericCatcher.addAll(rc);
// add default resource:
rc.register(TestResourceValidator.class);
// enable jersey specific validations (@Valid
rc.register(ValidationFeature.class);
ContextGenericTools.addJsr310(rc);
// add jackson to be discover when we are ins standalone server
rc.register(JacksonFeature.class);
LOGGER.info(" ==> {}", new DbConfig());
LOGGER.info("OAuth service {}", getBaseURI());
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
final HttpServer serverLink = this.server;
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
LOGGER.warn("Stopping server..");
serverLink.shutdownNow();
}
}, "shutdownHook"));
// ===================================================================
// start periodic update of the token ...
// ===================================================================
this.keyUpdater = new UpdateJwtPublicKey();
this.keyUpdater.start();
// ===================================================================
// run JERSEY
// ===================================================================
try {
this.server.start();
LOGGER.info("Jersey app started at {}", getBaseURI());
} catch (final Exception e) {
LOGGER.error("There was an error while starting Grizzly HTTP server.");
e.printStackTrace();
}
}
public void stop() {
if (this.server != null) {
this.server.shutdownNow();
this.server = null;
}
}
public void stopOther() {
this.keyUpdater.kill();
try {
this.keyUpdater.join(4000, 0);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,19 @@
package test.kar.archidata.hybernateValidator;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebLauncherTest extends WebLauncher {
final private static Logger LOGGER = LoggerFactory.getLogger(WebLauncherTest.class);
public WebLauncherTest() {
LOGGER.debug("Configure REST system");
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12345/test/api/";
// Enable the test mode permit to access to the test token (never use it in production).
ConfigBaseVariable.testMode = "true";
// ConfigBaseVariable.dbPort = "3306";
}
}

View File

@ -0,0 +1,21 @@
package test.kar.archidata.hybernateValidator.model;
import java.util.List;
import org.kar.archidata.annotation.checker.ReadOnlyField;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
public class ValidatorModel {
@ReadOnlyField
public String value;
@Size(max = 5)
public String data;
@Valid
public List<ValidatorSubModel> multipleElement;
@Valid
public ValidatorSubModel subElement;
}

View File

@ -0,0 +1,8 @@
package test.kar.archidata.hybernateValidator.model;
import jakarta.validation.constraints.Size;
public class ValidatorSubModel {
@Size(min = 2)
public String data;
}

View File

@ -0,0 +1,32 @@
package test.kar.archidata.hybernateValidator.resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.PermitAll;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import test.kar.archidata.apiExtern.resource.TestResource;
import test.kar.archidata.hybernateValidator.model.ValidatorModel;
@Path("/TestResourceValidator")
@Produces({ MediaType.APPLICATION_JSON })
public class TestResourceValidator {
private static final Logger LOGGER = LoggerFactory.getLogger(TestResource.class);
@POST
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public void post(final @QueryParam("queryParametersName") @Min(5) Long value, final @Valid ValidatorModel data)
throws Exception {
return;
}
}