簡體   English   中英

class.newInstance創建所有屬性為null的Object

[英]class.newInstance creates Object with all properties being null

我有一個需要像這樣動態初始化的類:

void doSth(classsuffix) throws Exception {

    String classname = "org.test.classname" + classsuffix; // classsuffix is dynamic

    Class<?> clazz;
    clazz = Class.forName(classname);

    TestInterface test = (TestInterface) clazz.newInstance();
    test.doStuff();
}

與示例類配對(遵循相同模式的許多示例之一):

public class classnameOne implements TestInterface {

    @Inject
    private Logger log;

    // ...

    @Override
    public void doStuff() {
        // Do stuff 

        log.info("done");
    }
}

問題是初始化時classnameOne類中的log將為null ,因此log.info()調用將引發NullPointerException。

我需要那個記錄器,所以用newInstance()創建類時是否有可能初始化注入的屬性?

還是有其他可能性基於字符串動態創建對象?

首先,您正在使用CDI,因此即使該文件完全為空,也需要將bean.xml文件放入META-INF中,否則它將無法正常工作。

例:

<beans xmlns="http://java.sun.com/xml/ns/javaee" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
  http://java.sun.com/xml/ns/javaee
  http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

</beans>

然后,您想注入記錄器,但是需要一個生產者,一個簡單的方法是:

public class LoggerProducer {
    @Produces
    public Logger produceLogger(InjectionPoint injectionPoint) {
        return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
    }
}

同樣重要的是,將暫時性關鍵字添加到您的logger屬性中,因為Produce無法產生不可序列化的實例。

public class classnameOne implements TestInterface{

    @Inject
    private transient Logger log;

// Some more functions and stuff

}

有趣的讀物:

  1. https://dzone.com/articles/cdi-di-p1
  2. http://www.devsniper.com/injectable-logger-with-cdi/

更新

如果您堅持使用Class :: newInstance()方法,則可以通過以下方式進行操作:

  1. 向您的TestInterface添加一個方法,該方法將返回一個TestInterface對象,並將其命名為getInstance()

     public interface TestInterface { public TestInterface getInstance(); } 
  2. 在您的每個類中實現該方法

     public class classnameOne implements TestInterface { @Inject private transient Logger log; public TestInterface getInstance() { return new classnameOne(); } } 
  3. 只需將以前的代碼添加到使用構造函數檢索具體實例的新方法即可(將進行適當的依賴注入):

     void doSth(classsuffix) throws Exception { String classname = "org.test.classname"+classsuffix; //classsuffix is dynamic Class<?> clazz; clazz = Class.forName(classname); TestInterface test = ((TestInterface) clazz.newInstance()).getInstance(); } 

它不漂亮,聞起來很香,但它確實可以滿足您的要求。

PD:注入注釋不適用於Constructor :: newInstance()或Class :: newInstance(),因此我想這將是您想要做的最接近的方法。

AutowireCapableBeanFactory可能對您的問題有所幫助,但請注意,這種方法有點臭,在典型的用例中不建議使用。 請參閱此鏈接:

https://stackoverflow.com/a/52355649/6223518

我找到了更好的解決方案

使用CDI.current()對象:

class TestClass {
    @Inject
    ClassnameCollection collection; // Inject


    void doSth(classsuffix) throws Exception {

        dynamicObject = CDI.current().select(
            (Class<TestInterface>) Class.forName("org.test.Classname" + suffix)).get();

        dynamicObject.doStuff();
    }
}

一個示例類供參考:

public class ClassnameOne implements TestInterface {

    @Inject
    private Logger log;

    // ...

    @Override
    public void doStuff() {
        // Do stuff 

        log.info("done");
    }
}

使用此解決方案,無需對現有類或類似內容進行任何更改。

舊版本

我可能找到的最佳解決方案是這樣的:

創建所有可用類的集合:

public class ClassnameCollection {
    @Inject
    public ClassnameOne classnameOne;
    @Inject
    public ClassnameTwo classnameTwo;

    // ...
}

並將其注入您想要動態類的類中:

class TestClass {
    @Inject
    ClassnameCollection collection; // Inject


    void doSth(classsuffix) throws Exception {

        Class collectionClass = ClassnameCollection.class;

        Field collectionField = collectionClass.getDeclaredField("classname" + suffix); // Get the declared field by String
        TestInterface dynamicObject = (TestInterface) collectionField.get(collection); // There you have the dynamic object with all the subclasses (for example Logger) initialized

        dynamicObject.doStuff();
    }
}

一個示例類供參考:

public class ClassnameOne implements TestInterface {

    @Inject
    private Logger log;

    // ...

    @Override
    public void doStuff() {
        // Do stuff 

        log.info("done");
    }
}

老實說,這是最好的解決方案,因為它不會更改任何子類,並且維護起來非常容易(只需在ClassnameCollection類中添加一個新的Inject )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM