From 1bc7725230d86e9e9348146249d2fa885c88e371 Mon Sep 17 00:00:00 2001 From: Karl Schrab Date: Wed, 19 Jul 2023 18:06:16 +0200 Subject: [PATCH] feat: allow to set a classloader for PackageSpecificTypeAdapter Signed-off-by: Karl Schrab --- .../util/gson/PackageSpecificTypeAdapter.java | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/mosaic-utils/src/main/java/org/eclipse/mosaic/lib/util/gson/PackageSpecificTypeAdapter.java b/lib/mosaic-utils/src/main/java/org/eclipse/mosaic/lib/util/gson/PackageSpecificTypeAdapter.java index a5ea0bda8..f6c296bec 100644 --- a/lib/mosaic-utils/src/main/java/org/eclipse/mosaic/lib/util/gson/PackageSpecificTypeAdapter.java +++ b/lib/mosaic-utils/src/main/java/org/eclipse/mosaic/lib/util/gson/PackageSpecificTypeAdapter.java @@ -20,36 +20,73 @@ import com.google.gson.Gson; import com.google.gson.JsonParseException; import com.google.gson.TypeAdapterFactory; +import org.apache.commons.lang3.Validate; import java.util.LinkedList; import java.util.List; -public class PackageSpecificTypeAdapter extends AbstractTypeAdapterFactory { +/** + * This {@link TypeAdapterFactory} allows to create an object from JSON definition + * based on a "type" attribute. According to the value of the value in the "type" attribute, + * a class is loaded and an object of this class is instantiated. Since this explicitly works + * with simple class names only, a search space of possible packages need to be defined, which + * are used to resolve the actual class. + */ +public final class PackageSpecificTypeAdapter extends AbstractTypeAdapterFactory { + + /** + * Holds all package names which are used to search for suitable classes to instantiate based on the given type name. + */ private final List packageNames = new LinkedList<>(); + /** + * The class loader to load the given class from. + */ + private ClassLoader classLoader = PackageSpecificTypeAdapter.class.getClassLoader(); + public PackageSpecificTypeAdapter(TypeAdapterFactory parentFactory, Gson gson) { super(parentFactory, gson); } + /** + * Adds the package of the given class to the search space. All classes within this package + * are candidates to be loaded by a given type name. + */ public PackageSpecificTypeAdapter searchInPackageOfClass(Class clazz) { return searchInPackage(clazz.getPackage()); } + /** + * Adds the given package to the search space. All classes within this package + * are candidates to be loaded by a given type name. + */ public PackageSpecificTypeAdapter searchInPackage(Package searchPackage) { return searchInPackage(searchPackage.getName()); } + /** + * Adds the given fully qualified package name to the search space. All classes + * within the given package are candidates to be loaded by a given type name. + */ public PackageSpecificTypeAdapter searchInPackage(String packageName) { packageNames.add(packageName); return this; } + /** + * Defines a specific class loader from which the searched classes are loaded. + */ + public PackageSpecificTypeAdapter withClassLoader(ClassLoader classLoader) { + this.classLoader = Validate.notNull(classLoader, "Given class loader must not be null"); + return this; + } + @Override protected Class fromTypeName(String type) { Class returnClass = null; for (String searchPackage : packageNames) { try { - returnClass = Class.forName(searchPackage + "." + type); + returnClass = classLoader.loadClass(searchPackage + "." + type); } catch (ClassNotFoundException ignored) { // nop }