Compare commits

...

5 Commits

15 changed files with 244 additions and 42 deletions

View File

@ -346,12 +346,15 @@ public class AnnotationTools {
return element.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
}
public static boolean isdefaultNotRead(final Field element) {
public static boolean isDefaultNotRead(final Field element) {
return element.getDeclaredAnnotationsByType(DataNotRead.class).length != 0;
}
public static boolean isIdField(final Field element) {
return element.getDeclaredAnnotationsByType(Id.class).length != 0;
if (element.getDeclaredAnnotationsByType(Id.class).length != 0) {
return true;
}
return element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class).length != 0;
}
// Note: delete field can not be renamed with OptionRenameColumn

View File

@ -0,0 +1,14 @@
package org.kar.archidata.converter.jackson;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class JacksonModules {
public static SimpleModule getAllModules() {
final SimpleModule module = new SimpleModule();
module.addSerializer(ObjectId.class, new ObjectIdSerializer());
module.addDeserializer(ObjectId.class, new ObjectIdDeserializer());
return module;
}
}

View File

@ -0,0 +1,16 @@
package org.kar.archidata.converter.jackson;
import java.io.IOException;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class ObjectIdDeserializer extends JsonDeserializer<ObjectId> {
@Override
public ObjectId deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
return new ObjectId(p.getValueAsString());
}
}

View File

@ -0,0 +1,17 @@
package org.kar.archidata.converter.jackson;
import java.io.IOException;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class ObjectIdSerializer extends JsonSerializer<ObjectId> {
@Override
public void serialize(final ObjectId value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeString(value.toHexString());
}
}

View File

@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.Limit;
@ -19,6 +20,7 @@ import org.kar.archidata.db.DbIoFactory;
import org.kar.archidata.db.DbIoMorphia;
import org.kar.archidata.db.DbIoSql;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -96,11 +98,11 @@ public abstract class DBAccess implements Closeable {
if (idKey == null) {
throw new DataAccessException("Try to identify the ID type and object was null.");
}
final String fieldName = AnnotationTools.getFieldName(idField, options).inTable();
final FieldName fieldName = AnnotationTools.getFieldName(idField, options);
final List<OptionSpecifyType> specificTypes = options.get(OptionSpecifyType.class);
if (typeClass == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(fieldName)) {
if (specify.name.equals(fieldName.inStruct())) {
typeClass = specify.clazz;
LOGGER.trace("Detect overwrite of typing ... '{}' => '{}'", typeClass.getCanonicalName(),
specify.clazz.getCanonicalName());
@ -115,7 +117,7 @@ public abstract class DBAccess implements Closeable {
}
throw new DataAccessException("Request update with the wrong type ...");
}
return new QueryCondition(fieldName, "=", idKey);
return new QueryCondition(fieldName.inTable(), "=", idKey);
}
// TODO: manage insert batch...
@ -132,7 +134,7 @@ public abstract class DBAccess implements Closeable {
// seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated...
public <T> T insertWithJson(final Class<T> clazz, final String jsonData) throws Exception {
final ObjectMapper mapper = new ObjectMapper();
final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
// parse the object to be sure the data are valid:
final T data = mapper.readValue(jsonData, clazz);
return insert(data);
@ -164,7 +166,7 @@ public abstract class DBAccess implements Closeable {
if (options.get(Condition.class).size() == 0) {
throw new DataAccessException("request a updateWhereWithJson without any condition");
}
final ObjectMapper mapper = new ObjectMapper();
final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
// parse the object to be sure the data are valid:
final T data = mapper.readValue(jsonData, clazz);
// Read the tree to filter injection of data:

View File

@ -665,7 +665,7 @@ public class DBAccessMorphia extends DBAccess {
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isdefaultNotRead(elem);
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
@ -798,7 +798,7 @@ public class DBAccessMorphia extends DBAccess {
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isdefaultNotRead(elem);
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}

View File

@ -1329,7 +1329,7 @@ public class DBAccessSQL extends DBAccess {
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isdefaultNotRead(elem);
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
@ -1449,7 +1449,7 @@ public class DBAccessSQL extends DBAccess {
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isdefaultNotRead(elem);
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
@ -1461,7 +1461,7 @@ public class DBAccessSQL extends DBAccess {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(elem.getName())) {
type = specify.clazz;
LOGGER.trace("Detect overwrite of typing ... '{}' => '{}'",
LOGGER.trace("Detect overwrite of typing var={} ... '{}' => '{}'", elem.getName(),
elem.getType().getCanonicalName(), specify.clazz.getCanonicalName());
break;
}

View File

@ -24,6 +24,7 @@ import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OrderBy;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.kar.archidata.tools.DateTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -391,7 +392,7 @@ public class DataExport {
}
if (MediaType.APPLICATION_JSON.equals(accept)) {
LOGGER.info("Start mapping josn");
final ObjectMapper objectMapper = new ObjectMapper();
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
LOGGER.info("Start find modules josn");
objectMapper.findAndRegisterModules();
LOGGER.info("Start map object");

View File

@ -52,7 +52,7 @@ public class AddOnDataJson implements DataAccessAddOn {
if (data == null) {
ps.setNull(iii.value, Types.VARCHAR);
}
final ObjectMapper objectMapper = new ObjectMapper();
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
final String dataString = objectMapper.writeValueAsString(data);
ps.setString(iii.value, dataString);
iii.inc();
@ -108,7 +108,7 @@ public class AddOnDataJson implements DataAccessAddOn {
}
final String jsonData = rs.getString(count.value);
if (!rs.wasNull()) {
final ObjectMapper objectMapper = new ObjectMapper();
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
if (field.getType() == List.class) {
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];

View File

@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.annotation.DataJson;
@ -25,6 +26,7 @@ import org.kar.archidata.dataAccess.options.OptionRenameColumn;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -69,7 +71,7 @@ public class AddOnDataJson implements DataAccessAddOn {
if (data == null) {
ps.setNull(iii.value, Types.VARCHAR);
}
final ObjectMapper objectMapper = new ObjectMapper();
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
final String dataString = objectMapper.writeValueAsString(data);
ps.setString(iii.value, dataString);
iii.inc();
@ -117,54 +119,85 @@ public class AddOnDataJson implements DataAccessAddOn {
final CountInOut count,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final List<OptionSpecifyType> specificTypes = options.get(OptionSpecifyType.class);
final String jsonData = rs.getString(count.value);
count.inc();
if (!rs.wasNull()) {
final ObjectMapper objectMapper = new ObjectMapper();
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
if (field.getType() == List.class) {
final ParameterizedType listType = (ParameterizedType) field.getGenericType();
final Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
if (listClass == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(field.getName())) {
listClass = specify.clazz;
LOGGER.trace("Detect overwrite of typing var={} ... '{}' => '{}'", field.getName(),
listClass.getCanonicalName(), specify.clazz.getCanonicalName());
break;
}
}
}
if (listClass == Long.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});// field.getType());
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Long>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Float.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Float>>() {});// field.getType());
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Float>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Double.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Double>>() {});// field.getType());
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Double>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Integer.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Integer>>() {});// field.getType());
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Integer>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == Short.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Short>>() {});// field.getType());
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<Short>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == String.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});// field.getType());
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<String>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == UUID.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});// field.getType());
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<UUID>>() {});
field.set(data, dataParsed);
return;
}
if (listClass == ObjectId.class) {
final Object dataParsed = objectMapper.readValue(jsonData, new TypeReference<List<ObjectId>>() {});
field.set(data, dataParsed);
return;
}
LOGGER.warn("Maybe fail to translate Model in datajson list: List<{}>", listClass.getCanonicalName());
}
final TypeFactory typeFactory = objectMapper.getTypeFactory();
final JavaType fieldType = typeFactory.constructType(field.getGenericType());
final Object dataParsed = objectMapper.readValue(jsonData, fieldType);
field.set(data, dataParsed);
Class<?> listClass = field.getType();
if (listClass == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(field.getName())) {
listClass = specify.clazz;
LOGGER.trace("Detect overwrite of typing var={} ... '{}' => '{}'", field.getName(),
listClass.getCanonicalName(), specify.clazz.getCanonicalName());
break;
}
}
final JavaType javaType = typeFactory.constructType(listClass);
final Object dataParsed = objectMapper.readValue(jsonData, javaType);
field.set(data, dataParsed);
} else {
final JavaType fieldType = typeFactory.constructType(field.getGenericType());
final Object dataParsed = objectMapper.readValue(jsonData, fieldType);
field.set(data, dataParsed);
}
}
}

View File

@ -2,6 +2,7 @@ package org.kar.archidata.tools;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.converter.jackson.JacksonModules;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
@ -9,20 +10,25 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
public class ContextGenericTools {
public static ObjectMapper createObjectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
// Configure Jackson for dates and times
objectMapper.registerModule(new JavaTimeModule()); // Module for Java 8+ Date and Time API
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// configure the local serialization modules
objectMapper.registerModule(JacksonModules.getAllModules());
return objectMapper;
}
/**
* Add support of Jackson jsr310 for data and time serialization and un-serialization.
* @param rc Resource exception model.
*/
public static void addJsr310(final ResourceConfig rc) {
// Configure Jackson for dates and times
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule()); // Module for Java 8+ Date and Time API
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
final ObjectMapper objectMapper = createObjectMapper();
// configure jackson provider for JSON mapper
final JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
provider.setMapper(objectMapper);
// Record it on the Resource configuration
rc.register(provider);

View File

@ -108,7 +108,7 @@ public class JWTWrapper {
in.close();
// print result
LOGGER.debug(response.toString());
final ObjectMapper mapper = new ObjectMapper();
final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
final PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
rsaPublicJWK = RSAKey.parse(values.key);
return;

View File

@ -17,9 +17,7 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import jakarta.ws.rs.core.HttpHeaders;
@ -31,11 +29,7 @@ public class RESTApi {
public RESTApi(final String baseUrl) {
this.baseUrl = baseUrl;
this.mapper = new ObjectMapper();
// add by default support of LocalTime and LocalDate and LocalDateTime
this.mapper.registerModule(new JavaTimeModule()); // Module for Java 8+ Date and Time API
this.mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
this.mapper = ContextGenericTools.createObjectMapper();
}
public void setToken(final String token) {

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@ -21,6 +22,7 @@ import org.slf4j.LoggerFactory;
import test.kar.archidata.ConfigureDb;
import test.kar.archidata.StepwiseExtension;
import test.kar.archidata.dataAccess.model.SerializeListAsJson;
import test.kar.archidata.dataAccess.model.SerializeListAsJsonObjectId;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -138,4 +140,101 @@ public class TestListJson {
Assertions.assertEquals(firstDataInserted3, retrieve.data.get(1));
}
@Order(101)
@Test
public void testOIDTableInsertAndRetrieve() throws Exception {
final List<String> sqlCommand = DataFactory.createTable(SerializeListAsJsonObjectId.class);
if (ConfigureDb.da instanceof final DBAccessSQL daSQL) {
for (final String elem : sqlCommand) {
LOGGER.debug("request: '{}'", elem);
daSQL.executeSimpleQuery(elem);
}
}
}
@Order(102)
@Test
public void testOIDIO() throws Exception {
final SerializeListAsJsonObjectId test = new SerializeListAsJsonObjectId();
test.data = new ArrayList<>();
test.data.add(new ObjectId());
test.data.add(new ObjectId());
test.data.add(new ObjectId());
test.data.add(new ObjectId());
test.data.add(new ObjectId());
final SerializeListAsJsonObjectId insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData._id);
Assertions.assertNotNull(insertedData.data);
Assertions.assertEquals(5, insertedData.data.size());
Assertions.assertEquals(test.data.get(0), insertedData.data.get(0));
Assertions.assertEquals(test.data.get(1), insertedData.data.get(1));
Assertions.assertEquals(test.data.get(2), insertedData.data.get(2));
Assertions.assertEquals(test.data.get(3), insertedData.data.get(3));
Assertions.assertEquals(test.data.get(4), insertedData.data.get(4));
// Try to retrieve all the data:
final SerializeListAsJsonObjectId retrieve = ConfigureDb.da.get(SerializeListAsJsonObjectId.class,
insertedData._id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve._id);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(5, retrieve.data.size());
Assertions.assertEquals(test.data.get(0), retrieve.data.get(0));
Assertions.assertEquals(test.data.get(1), retrieve.data.get(1));
Assertions.assertEquals(test.data.get(2), retrieve.data.get(2));
Assertions.assertEquals(test.data.get(3), retrieve.data.get(3));
Assertions.assertEquals(test.data.get(4), retrieve.data.get(4));
}
@Order(103)
@Test
public void testOIDToolInsert() throws Exception {
final SerializeListAsJsonObjectId test = new SerializeListAsJsonObjectId();
test.data = new ArrayList<>();
final SerializeListAsJsonObjectId insertedData = ConfigureDb.da.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData._id);
Assertions.assertNotNull(insertedData.data);
Assertions.assertEquals(0, insertedData.data.size());
final ObjectId firstDataInserted1 = new ObjectId();
final ObjectId firstDataInserted2 = new ObjectId();
final ObjectId firstDataInserted3 = new ObjectId();
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData._id, "data",
firstDataInserted1);
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData._id, "data",
firstDataInserted2);
AddOnDataJson.addLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData._id, "data",
firstDataInserted3);
// Try to retrieve all the data:
SerializeListAsJsonObjectId retrieve = ConfigureDb.da.get(SerializeListAsJsonObjectId.class, insertedData._id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve._id);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(3, retrieve.data.size());
Assertions.assertEquals(firstDataInserted1, retrieve.data.get(0));
Assertions.assertEquals(firstDataInserted2, retrieve.data.get(1));
Assertions.assertEquals(firstDataInserted3, retrieve.data.get(2));
AddOnDataJson.removeLink(ConfigureDb.da, SerializeListAsJsonObjectId.class, "_id", insertedData._id, "data",
firstDataInserted2);
// Try to retrieve all the data:
retrieve = ConfigureDb.da.get(SerializeListAsJsonObjectId.class, insertedData._id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve._id);
Assertions.assertNotNull(retrieve.data);
Assertions.assertEquals(2, retrieve.data.size());
Assertions.assertEquals(firstDataInserted1, retrieve.data.get(0));
Assertions.assertEquals(firstDataInserted3, retrieve.data.get(1));
}
}

View File

@ -0,0 +1,17 @@
package test.kar.archidata.dataAccess.model;
import java.util.List;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.OIDGenericData;
import dev.morphia.annotations.Entity;
@Entity
public class SerializeListAsJsonObjectId extends OIDGenericData {
@DataJson
public List<ObjectId> data;
}