5

final パブリック クラスの変更に関して簡単な質問があります。いくつかの調査に基づいて、最終的なパブリック クラスは継承または実装できないようです。私の目標は、この最終パブリック クラス内の 1 つの最終静的変数を変更することです。

クラス名は: public final class 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");

authorizationthis から field を取り除きたいですDISALLOWED_HEADERS_SET。これを行う方法はありますか?

リフレクションはクラスを変更する 1 つの方法だと聞きました。これはApress/java-9-revealedを github に公開したもので、クラスの内部が明らかになるようです


このスレッド (質問) は XY 問題として識別されています。上記の問題の解決策が必要な理由について、詳細を説明してみます。この質問をするようになった理由を掘り下げる前に、この問題が現在どこにあるのかという現在の状況について説明します。

この問題はClevertap to Oracleによってすでに引き起こされていることを理解することが重要です。Oracle のリンクをたどると、この問題が認識され、 に更新されていることがわかりますJdk 11。オラクルがこの修正されたソース コードを次の に適用することを願っていますが、 が を表すJava 10という事実を考えると、その可能性は非常に低いです。そうは言っても、クレバータップのオープンスレッドが示唆するリフレクションを使用することが唯一の解決策です。Jdk 9Java 9

ここで、私が達成したことと理解しようとしていることを簡単に説明します。Java 言語を使用してプッシュ通知を APNs に送信するために開発しているフレームワークに取り組んでいます。1つの機能を除いてすべてが機能します。

[ Jetty、Netty、okhttp などのサードパーティ フレームワークに依存せずに APNs に通知を送信しようとしている人のために、近い将来、このフレームワークを GitHub を通じて共有します。]

通知を送信するための認証方法としてトークンを使用しようとすると、問題が発生します。Appleから提供された指示に従って、トークンの作成に成功しました。私がしなければならないのは、リクエストヘッダーにauthorizationキーとbearer <token>値を設定することだけです。ただし、jdk9.incubator.httpclient.setHeaderモジュールから派生したものを使用してこれらの値を設定すると、このフィールドは自動的に省略されます。前述のように、は一部であり、明らかに許可されていません。ユーザーがリクエスト ヘッダー フィールドのキー値として「承認」を設定しようとすると、それは削除されます。この問題を回避するための提案があれば。同じ問題に直面している他の人にとっては素晴らしく、役立つでしょう。authorizationDISALLOWED_HEADERS_SET


悪い知らせです...メソッドがjdk 9.0.4削除されsetSystemHeaderたので、使用したい場合は使用reflectionする必要がありますJdk 9.0.1


以前お約束したように、Pure Java コードを使用して通知を送信するための Java ライブラリを作成し、githubにプッシュしました。jdk10公開したアプリに基づいた古いバージョンを使用しました。古いバージョンは TLS 接続のみをサポートしていました。に基づく現在のバージョンjdk11は、APN にプッシュ通知を送信するための tls とトークン ベースの認証の両方をサポートしています。

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

この値は静的であるため、継承によって何を達成しようとしているのかは明確ではありません。しかし、アプリケーションを再コンパイルできる場合、オブジェクトの構成について考えたことはありますか? これは継承に代わるものであり、最終クラスまたは「乗算」継承の場合にポリモーフィックな動作をシミュレートするためによく使用されます。元のクラス(最終クラス)の代わりに新しいクラスを「注入」できる場合は、最終クラスのインスタンスを含む新しいクラスを作成し、そのメソッドをそれらに委任できます。同じ final static 変数を作成する必要はありません。

于 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 に答える