Home > Back-end >  java static method for abstract class
java static method for abstract class

Time:02-11

I have a java abstract class that declares the extended class as "JsonSerializable"

public abstract class JsonSerializable {
    private final String path;

    public JsonSerializable(String path) {
        this.path = path;
    }
} 

Now, if I try to "load" a class that extends JsonSerializable I need to get the "filepath" for the class I want to load. The way I am currently doing this is as follows:

private static <T extends JsonSerializable> T getNew(Class<T> tClass) throws [...] {
        return tClass.getDeclaredConstructor().newInstance();
}

But what if the constructing of a new class (of the type I am trying to load) has some side effects (e.g. upon initialization, the class "registers" itself inside another one) or if there IS no constructor with no arguments?

Is there any better way to do this? I don't want to create a "FileRegistry" class that just holds the file paths for each class.

CodePudding user response:

But what if the constructing of a new class (of the type I am trying to load) has some side effects (e.g. upon initialization, the class "registers" itself inside another one)

Constructor#newInstance invokes the constructor. If it has side effects, those things will happen. But note that ideally, constructors should only initialize the object and not have side effects (especially nothing that leak the object/publosh the this-reference before the constructor finishes.

or if there IS no constructor with no arguments?

In that case, getDeclaredConstructor() throws an exception. However, you can get all constructors using Class#getDeclaredConstructors.

However, you can specify that classes extending JsonSerializable must have a no-args-constructor with no side effects in the Javadoc of JsonSerializable.

While you can create new instances without invoking the constructor using Unsafe, this should be avoided as it would leave variables uninitialized likely resulting in future exceptions.

CodePudding user response:

IMHO this looks more like a use case for an annotation @JsonSerializable(path="some.path") on the classes that you want to load.

The code could look like this:

// JsonSerializable.java
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonSerializable {
    String path();
}

The annotation would be used on a class like this:

// Options.java
@JsonSerializable(path="filepath.ending")
public class Options {
    private String example_property;
    private int example_property2;

    public Options() {
    }
}

And the code that reads the annotation would then be:

private static <T> T getNew(Class<T> tClass) throws Exception {
    JsonSerializable annotation = tClass.getAnnotation(JsonSerializable.class);
    System.out.println(annotation.path()); // Just to show how the path is read
    // here you would insert code to read the class the way you need
    return tClass.getDeclaredConstructor().newInstance();
}
  • Related