调整 return 方法的值,该方法是单例且具有最终访问修饰符

Adjust return value of a method which is a singleton and has final access modifiers

我想从实例 class 调整方法的 return 值,我不太确定是否可以使用或不使用反射。我想不通,所以我想在这里问一下。假设我有以下 class Foo:

public final class Foo {

    private static final INSTANCE = new Foo()

    protected Foo() {}
    
    public final String getName() {
        return "Foo";
    }

    public static Foo getInstance() {
        return INSTANCE;
    }
    
}

一些上下文:

因此,对于这个基本示例,我想从方法 getName() 中获取 Bar returned 而不是 Foo.非常明确:

Foo foo = Foo.getInstance();
String name = foo.getName();
System.out.println(name) // --> prints "Bar"

我为什么需要这个?

好吧,我需要将这个 Foo 实例传递给另一个只接受 Foo 类型对象的方法。此方法将调用方法 getName() 并将进行一些额外的计算。

实际用例:

我会尝试提供更多背景信息,希望它会更清楚一些。构建器 class 中有一个方法接受 KeyManagerFactory 的实例,该方法称为 setKeyManagerFactory(KeyManagerFactory keyManagerFactory)。此构建器 class 将在 KeyManagerFactory 上内部调用 getKeyManagers 并且它将 return KeyManagers[]

KeyManagerFactory 是最终的 class,它根本没有 public 构造函数。 getKeyManager 方法也是最终的。我已经有一个 KeyManager[],所以我想将此 KeyManagerFactory 破解为 return 我自己的数组拥有的 KeyManagers,并将其提供给构建器。

通常 KeyManagerFactory 使用以下代码片段实例化:

KeyStore keyStore = ... //initialized keyStore
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
kmf.init(keyStore, keyPassword);

KeyManager[] keyManagers = kmf.getKeyManagers();

通过上面的代码片段,KeyManagerFactory 将 return 一个基于提供的 KeyStore 对象的 KeyManager 数组。我想要实现的是以某种方式 return 我的自定义 KeyManager 数组。

我还添加了KeyManagerFactory的反编译源代码:

package javax.net.ssl;

import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import sun.security.jca.GetInstance;
import sun.security.jca.GetInstance.Instance;

public class KeyManagerFactory {
    private Provider provider;
    private KeyManagerFactorySpi factorySpi;
    private String algorithm;

    public static final String getDefaultAlgorithm() {
        String var0 = (String)AccessController.doPrivileged(new PrivilegedAction<String>() {
            public String run() {
                return Security.getProperty("ssl.KeyManagerFactory.algorithm");
            }
        });
        if (var0 == null) {
            var0 = "SunX509";
        }

        return var0;
    }

    protected KeyManagerFactory(KeyManagerFactorySpi var1, Provider var2, String var3) {
        this.factorySpi = var1;
        this.provider = var2;
        this.algorithm = var3;
    }

    public final String getAlgorithm() {
        return this.algorithm;
    }

    public static final KeyManagerFactory getInstance(String var0) throws NoSuchAlgorithmException {
        Instance var1 = GetInstance.getInstance("KeyManagerFactory", KeyManagerFactorySpi.class, var0);
        return new KeyManagerFactory((KeyManagerFactorySpi)var1.impl, var1.provider, var0);
    }

    public static final KeyManagerFactory getInstance(String var0, String var1) throws NoSuchAlgorithmException, NoSuchProviderException {
        Instance var2 = GetInstance.getInstance("KeyManagerFactory", KeyManagerFactorySpi.class, var0, var1);
        return new KeyManagerFactory((KeyManagerFactorySpi)var2.impl, var2.provider, var0);
    }

    public static final KeyManagerFactory getInstance(String var0, Provider var1) throws NoSuchAlgorithmException {
        Instance var2 = GetInstance.getInstance("KeyManagerFactory", KeyManagerFactorySpi.class, var0, var1);
        return new KeyManagerFactory((KeyManagerFactorySpi)var2.impl, var2.provider, var0);
    }

    public final Provider getProvider() {
        return this.provider;
    }

    public final void init(KeyStore var1, char[] var2) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        this.factorySpi.engineInit(var1, var2);
    }

    public final void init(ManagerFactoryParameters var1) throws InvalidAlgorithmParameterException {
        this.factorySpi.engineInit(var1);
    }

    public final KeyManager[] getKeyManagers() {
        return this.factorySpi.engineGetKeyManagers();
    }
}

你可以这样做。 (您可以对私有字段使用 setAccessible(true))

public final class  Single {
    public String s;

    public Single() {
    }

    public String getS() {
        return s;
    }
}

public class Main {
    public static void main(String[] args) throws IllegalAccessException {
        Single single = new Single();
        single.getClass().getFields()[0].set(single, "Hmm");
        System.out.println(single.getS());
    }
}

在@tgdavies 的提示下,我能够完成我想要的。谢谢!

所以我所做的是创建了一个 KeyManagerFactoryWrapper,其中包含一个名为 KeyManagerFactorySpiWrapper 的自定义 KeyManagerFactorySpi

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.KeyManagerFactorySpi;
import javax.net.ssl.ManagerFactoryParameters;
import java.security.KeyStore;
import java.security.Provider;

/**
 * @author Hakan Altindag
 */
public class KeyManagerFactoryWrapper extends KeyManagerFactory {

    private static final String KEY_MANAGER_FACTORY_ALGORITHM = "no-algorithm";
    private static final Provider PROVIDER = new Provider("", 1.0, "") {};

    public KeyManagerFactoryWrapper(KeyManager keyManager) {
        super(new KeyManagerFactorySpiWrapper(keyManager), PROVIDER, KEY_MANAGER_FACTORY_ALGORITHM);
    }

    private static class KeyManagerFactorySpiWrapper extends KeyManagerFactorySpi {

        private final KeyManager[] keyManagers;

        public KeyManagerFactorySpiWrapper(KeyManager keyManager) {
            this.keyManagers = new KeyManager[]{keyManager};
        }

        @Override
        protected void engineInit(KeyStore keyStore, char[] keyStorePassword) {
            // ignoring
        }

        @Override
        protected void engineInit(ManagerFactoryParameters managerFactoryParameters) {
            // ignoring
        }

        @Override
        protected KeyManager[] engineGetKeyManagers() {
            return keyManagers;
        }
    }
}

我能够通过 TrustManagerFactory 实现同样的效果:

import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.TrustManagerFactorySpi;
import java.security.KeyStore;
import java.security.Provider;

/**
 * @author Hakan Altindag
 */
public class TrustManagerFactoryWrapper extends TrustManagerFactory {

    private static final String KEY_MANAGER_FACTORY_ALGORITHM = "no-algorithm";
    private static final Provider PROVIDER = new Provider("", 1.0, "") {};

    public TrustManagerFactoryWrapper(TrustManager trustManager) {
        super(new TrustManagerFactorySpiWrapper(trustManager), PROVIDER, KEY_MANAGER_FACTORY_ALGORITHM);
    }

    private static class TrustManagerFactorySpiWrapper extends TrustManagerFactorySpi {

        private final TrustManager[] trustManagers;

        public TrustManagerFactorySpiWrapper(TrustManager trustManager) {
            this.trustManagers = new TrustManager[]{trustManager};
        }

        @Override
        protected void engineInit(KeyStore keyStore) {
            // ignoring
        }

        @Override
        protected void engineInit(ManagerFactoryParameters managerFactoryParameters) {
            // ignoring
        }

        @Override
        protected TrustManager[] engineGetTrustManagers() {
            return trustManagers;
        }
    }   
}

现在我可以使用以下代码片段轻松创建 KeyManagerFactory 和 TrustManagerFactory:

KeyManager keyManager = ...; //initialised keyManager
TrustManager trustManager = ...; //initialised trustManager

KeyManagerFactory = new KeyManagerFactoryWrapper(keyManager);
TrustManagerFactory = new TrustManagerFactoryWrapper(keyManager);