feat: implement map-object conversion with a safer method

If you still want to use the unsafe version, please use
com.onixbyte:map-util-unsafe.
This commit is contained in:
zihluwang
2024-12-26 20:15:38 +08:00
parent 8f6dfce4b3
commit 2d3a0745f5
2 changed files with 21 additions and 92 deletions
@@ -31,7 +31,7 @@ import java.util.Optional;
* Please see documentation for more information. * Please see documentation for more information.
* *
* @author zihluwang * @author zihluwang
* @version 1.4.2 * @version 1.7.0
* @since 1.0.0 * @since 1.0.0
*/ */
@Slf4j @Slf4j
@@ -40,16 +40,13 @@ public final class MapUtil {
/** /**
* Converts an object to a map by mapping the field names to their corresponding values. * Converts an object to a map by mapping the field names to their corresponding values.
* *
* @param <T> the type of the object * @param <T> the type of the object
* @param entity the object to be converted to a map * @param entity the object to be converted to a map
* @param adapters adapts the entity for mapping to a map * @param adapter adapts the entity for mapping to a map
* @return a map representing the fields and their values of the object * @return a map representing the fields and their values of the object
*/ */
public static <T> Map<String, Object> objectToMap(T entity, public static <T> Map<String, Object> objectToMap(T entity, ObjectMapAdapter<T> adapter) {
Map<String, ObjectMapAdapter<T, ?>> adapters) { return adapter.toMap(entity);
var resultMap = new HashMap<String, Object>();
adapters.forEach((fieldName, adapter) -> resultMap.put(fieldName, adapter.fetch(entity)));
return resultMap;
} }
/** /**
@@ -57,64 +54,17 @@ public final class MapUtil {
* map entries. * map entries.
* *
* @param objectMap the map representing the fields and their values * @param objectMap the map representing the fields and their values
* @param entity an empty entity of the target class * @param adapter the adapter to execute the setter for the entity
* @param adapters the adapters to execute the setter for the entity
* @param <T> the type of the object to be created * @param <T> the type of the object to be created
* @return an object of the specified type with the field values set from the map * @return an object of the specified type with the field values set from the map
*/ */
public static <T> T mapToObject(Map<String, Object> objectMap, public static <T> T mapToObject(Map<String, Object> objectMap, ObjectMapAdapter<T> adapter) {
T entity, return adapter.toObject(objectMap);
Map<String, ObjectMapAdapter<T, ?>> adapters) {
adapters.forEach((fieldName, adapter) -> Optional.ofNullable(objectMap)
.map((data) -> data.get(fieldName))
.ifPresent((fieldValue) -> adapter.setValue(entity, fieldValue)));
return entity;
} }
/** /**
* Retrieves the value of a field from an object using reflection. * Private constructor prevent class being instantiated.
*
* @param <E> the type of the entity
* @param <T> the type of the field value
* @param entity the object from which to retrieve the field value
* @param adapter the adapter to execute the getter
* @return the value of the field in the object, or null if the field does not exist or cannot
* be accessed
*/ */
public static <E, T> T getFieldValue(E entity, ObjectMapAdapter<E, T> adapter) {
return adapter.fetch(entity);
}
/**
* Sets the value of a field in an object using reflection.
*
* @param <E> the type of the entity
* @param <T> the type of the field value
* @param entity the object in which to set the field value
* @param adapter the adapter to execute the setter
* @param fieldValue the value to be set
*/
public static <E, T> void setFieldValue(E entity,
ObjectMapAdapter<E, T> adapter,
Object fieldValue) {
adapter.setValue(entity, fieldValue);
}
/**
* Casts the specified value to the required type with Optional.
*
* @param value the value to be cast
* @param requiredType the type to which the value should be cast
* @param <T> the type to which the value should be cast
* @return the cast value, or {@code null} if the value is not an instance of the requiredType
*/
public static <T> T cast(Object value, Class<T> requiredType) {
return Optional.ofNullable(requiredType)
.filter((clazz) -> clazz.isInstance(value))
.map((clazz) -> clazz.cast(value))
.orElse(null);
}
private MapUtil() { private MapUtil() {
} }
} }
@@ -17,53 +17,32 @@
package com.onixbyte.devkit.utils; package com.onixbyte.devkit.utils;
import java.util.function.BiConsumer; import java.util.Map;
import java.util.function.Function;
/** /**
* Adapts an Object to a Map, making conversion between Map and Object much more safe. * Adapts an Object to a Map, making conversion between Map and Object much more safe.
* *
* @param <E> entity type
* @param <T> field type * @param <T> field type
* @author zihluwang * @author zihluwang
* @version 1.4.2 * @version 1.7.0
* @since 1.4.2 * @since 1.4.2
*/ */
public class ObjectMapAdapter<E, T> { public interface ObjectMapAdapter<T> {
private final Function<E, T> getter;
private final BiConsumer<E, Object> setter;
/** /**
* Create an adapter. * Convert an object to a map.
* *
* @param getter the getter of the field * @param element the element that will be converted to Map
* @param setter the setter of the field * @return a Map that is converted from the element
*/ */
public ObjectMapAdapter(Function<E, T> getter, BiConsumer<E, Object> setter) { Map<String, Object> toMap(T element);
this.getter = getter;
this.setter = setter;
}
/** /**
* Get data from the entity. * Convert a Map to an object.
* *
* @param entity the source of the data * @param map the map that will be converted to Object
* @return the data * @return the object that is converted from the Map
*/ */
public T fetch(E entity) { T toObject(Map<String, Object> map);
return getter.apply(entity);
}
/**
* Set value to the entity.
*
* @param entity the target of the data
* @param value the value
*/
public void setValue(E entity, Object value) {
setter.accept(entity, value);
}
} }