5

我有一个关于修改最终公共课程的快速问题。根据一些研究,似乎最终的公共类不能被继承或实现。我的目标是在这个最终的公共类中更改一个最终的静态变量。

类名是:公共最终类Utils

private static final Set<String> DISALLOWED_HEADERS_SET = Set.of(
    "authorization", "connection", "cookie", "content-length",
    "date", "expect", "from", "host", "origin", "proxy-authorization",
    "referer", "user-agent", "upgrade", "via", "warning");

我想摆脱authorization这个领域DISALLOWED_HEADERS_SET。有没有办法做到这一点?

我听说反射是修改类的一种方法。这是一个Apress/java-9-revealed to a github,它似乎揭示了类的内容


此线程(问题)已被确定为 XY 问题。我将尝试用更多信息解释为什么我想要解决上述问题。在深入探讨促使我提出这个问题的原因之前,我将介绍一下这个问题目前所处的现状。

重要的是要了解,Clevertap已经向Oracle提出了这个问题。如果您关注 Oracle 链接,您可以看到此问题已被确认并更新为Jdk 11. 希望 Oracle 将这个固定的源代码应用到即将到来Java 10的. 话虽这么说,唯一的解决方案是使用clevertap中的开放线程建议的反射。Jdk 9Java 9

现在,我将简要解释一下我所取得的成就并试图弄清楚。我一直在研究我一直在开发的框架,用于使用 Java 语言向 APNs 发送推送通知。除了一项功能外,一切正常。

[我将在不久的将来通过 GitHub 为那些试图在不依赖第三方框架(例如 Jetty、Netty 或 okhttp)的情况下向 APNs 发送通知的人分享这个框架。]

当我尝试使用令牌作为身份验证方式发送通知时,问题就出现了。我已按照Apple提供的说明成功创建了令牌。我所要做的就是使用authorization键和bearer <token>值设置请求标头。但是,当我使用.setHeader派生自jdk9.incubator.httpclient模块来设置这些值时,它会自动省略该字段。如前所述,authorization是其中的一部分,DISALLOWED_HEADERS_SET显然是不允许的。如果用户尝试将“授权”设置为请求头字段的键值,则会将其删除。如果您有任何解决此问题的建议。对于面临同样问题的其他人来说,这将是很棒的和有帮助的。


坏消息伙计们......jdk 9.0.4删除了setSystemHeader方法,所以如果你想使用reflection,你需要使用Jdk 9.0.1


如前所述,我创建了用于使用纯 java 代码发送通知的 java 库并将其推送到github。我使用了基于jdk10我发布的应用程序的旧版本。旧版本仅支持 tls 连接。现在基于的当前版本jdk11同时支持 tls 和基于令牌的身份验证,用于向 APNs 发送推送通知。

4

4 回答 4

2

只是从集合中删除该值对您有用吗?像这样的东西:

        Field f = Utils.class.getDeclaredField("DISALLOWED_HEADERS_SET");
        f.setAccessible(true);

        @SuppressWarnings("unchecked")
        Set<String> headers = (Set<String>)f.get(null);        
        headers.remove("authorization"); 
于 2018-02-20T21:18:31.593 回答
1

因为这个值是静态的,所以我不清楚你将通过继承实现什么。但是,如果您可以重新编译您的应用程序,您是否考虑过对象组合?这可以替代继承,并且通常用于在最终类或“乘法”继承的情况下模拟多态行为。如果您可以“注入”新类而不是原始类(即最终类),则可以组成一个包含最终类实例并将其方法委托给它们的新类。无需创建相同的最终静态变量。

于 2018-02-20T20:29:07.987 回答
-1

如果你想依靠反思,这可能会有所帮助-

Class reqClz = request.getClass();

Method setHeaderMethod = reqClz.getDeclaredMethod("setSystemHeader", String.class, String.class);
setHeaderMethod.setAccessible(true);

setHeaderMethod.invoke(request, "authorization", "<token>");

您可能必须使用 VM arg 打开孵化器模块的包:-

--add-opens jdk.incubator.httpclient/jdk.incubator.http=<your-package x.y.z>

或者

也在想,这里的另一种方法可能是修补模块内容

--patch-module <module>=<file>(<pathsep><file>)*

对于jdk.incubator.http.internal.common.Utils课程,但建议不要超过测试或调试目的。

于 2018-02-20T20:31:15.457 回答
-2

以下代码允许您更改私有静态字段(非最终)的值:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class SetFinalField {

    @SuppressWarnings("unchecked")
    public final static void main(String[] args) throws Exception {
        System.out.println("elements before: " + SetTarget.DISALLOWED_HEADERS_SET);
        Field f = SetTarget.class.getDeclaredField("DISALLOWED_HEADERS_SET");
        f.setAccessible(true);
        ArrayList<String> l = new ArrayList<String>();
        l.addAll((Set<String>) f.get(null));
        l.remove("authorization");
        HashSet<String> hs = new HashSet<>();
        hs.addAll(l);
        f.set(null, Collections.unmodifiableSet(hs));
        System.out.println("elements after: " + SetTarget.DISALLOWED_HEADERS_SET);
    }

    public final static class SetTarget {
        private static Set<String> DISALLOWED_HEADERS_SET;

        static {
            HashSet<String> l = new HashSet<>();
            Collections.addAll(l, new String[]{"authorization", "connection", "cookie", "content-length",
                    "date", "expect", "from", "host", "origin", "proxy-authorization",
                    "referer", "user-agent", "upgrade", "via", "warning"});
            DISALLOWED_HEADERS_SET = Collections.unmodifiableSet(l);
        }
    }

}

如果您将字段更改final为此将被阻止,因此请回答您的问题:使用反射无法执行您当前尝试执行的操作。有一种方法,虽然通过使用 JNI,但你不想那样做。无论您尝试完成什么,您都应该尝试找到不同的解决方案,例如,通过检查正在使用此标头的类是否可以使用一组备用的不允许的标头值进行配置,或者按照@nullpointer 描述的方式进行。

于 2018-02-20T20:43:48.623 回答