it-swarm.com.de

Verwendung von Cookies mit der Android-Volleybibliothek

Kann jemand mit der Bibliothek com.Android.volley ein Sitzungscookie an die Anforderung anhängen? Wenn ich mich bei einer Website anmelde, wird mir ein Sitzungscookie angezeigt. Der Browser sendet das Cookie bei jeder nachfolgenden Anfrage zurück. Volley scheint das nicht zu tun, zumindest nicht automatisch.

Vielen Dank.

51
Rastio

vmirinov hat recht!

So habe ich das Problem gelöst:

Klasse beantragen:

public class StringRequest extends com.Android.volley.toolbox.StringRequest {

    private final Map<String, String> _params;

    /**
     * @param method
     * @param url
     * @param params
     *            A {@link HashMap} to post with the request. Null is allowed
     *            and indicates no parameters will be posted along with request.
     * @param listener
     * @param errorListener
     */
    public StringRequest(int method, String url, Map<String, String> params, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, listener, errorListener);

        _params = params;
    }

    @Override
    protected Map<String, String> getParams() {
        return _params;
    }

    /* (non-Javadoc)
     * @see com.Android.volley.toolbox.StringRequest#parseNetworkResponse(com.Android.volley.NetworkResponse)
     */
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        // since we don't know which of the two underlying network vehicles
        // will Volley use, we have to handle and store session cookies manually
        MyApp.get().checkSessionCookie(response.headers);

        return super.parseNetworkResponse(response);
    }

    /* (non-Javadoc)
     * @see com.Android.volley.Request#getHeaders()
     */
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = super.getHeaders();

        if (headers == null
                || headers.equals(Collections.emptyMap())) {
            headers = new HashMap<String, String>();
        }

        MyApp.get().addSessionCookie(headers);

        return headers;
    }
}

und MyApp:

public class MyApp extends Application {
    private static final String SET_COOKIE_KEY = "Set-Cookie";
    private static final String COOKIE_KEY = "Cookie";
    private static final String SESSION_COOKIE = "sessionid";

    private static MyApp _instance;
  private RequestQueue _requestQueue;
  private SharedPreferences _preferences;

    public static MyApp get() {
        return _instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        _instance = this;
            _preferences = PreferenceManager.getDefaultSharedPreferences(this);
        _requestQueue = Volley.newRequestQueue(this);
    }

    public RequestQueue getRequestQueue() {
        return _requestQueue;
    }


    /**
     * Checks the response headers for session cookie and saves it
     * if it finds it.
     * @param headers Response Headers.
     */
    public final void checkSessionCookie(Map<String, String> headers) {
        if (headers.containsKey(SET_COOKIE_KEY)
                && headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
                String cookie = headers.get(SET_COOKIE_KEY);
                if (cookie.length() > 0) {
                    String[] splitCookie = cookie.split(";");
                    String[] splitSessionId = splitCookie[0].split("=");
                    cookie = splitSessionId[1];
                    Editor prefEditor = _preferences.edit();
                    prefEditor.putString(SESSION_COOKIE, cookie);
                    prefEditor.commit();
                }
            }
    }

    /**
     * Adds session cookie to headers if exists.
     * @param headers
     */
    public final void addSessionCookie(Map<String, String> headers) {
        String sessionId = _preferences.getString(SESSION_COOKIE, "");
        if (sessionId.length() > 0) {
            StringBuilder builder = new StringBuilder();
            builder.append(SESSION_COOKIE);
            builder.append("=");
            builder.append(sessionId);
            if (headers.containsKey(COOKIE_KEY)) {
                builder.append("; ");
                builder.append(headers.get(COOKIE_KEY));
            }
            headers.put(COOKIE_KEY, builder.toString());
        }
    }

}
40
Rastio

Volley stellt keine HTTP-Anfragen selbst ab und verwaltet Cookies daher nicht direkt. Stattdessen wird dazu eine Instanz von HttpStack verwendet. Es gibt zwei Hauptimplementierungen:

  • HurlStack: Verwendet HttpUrlConnection unter der Haube
  • HttpClientStack: Verwendet Apache HttpClient unter der Haube

Die Cookie-Verwaltung liegt in der Verantwortung dieser HttpStacks. Und sie behandeln Cookies unterschiedlich.

Wenn Sie <2.3 unterstützen müssen, sollten Sie den HttpClientStack verwenden:

Konfigurieren Sie eine HttpClient-Instanz und übergeben Sie diese an Volley, damit sie unter der Haube verwendet werden kann:

// If you need to directly manipulate cookies later on, hold onto this client
// object as it gives you access to the Cookie Store
DefaultHttpClient httpclient = new DefaultHttpClient();

CookieStore cookieStore = new BasicCookieStore();
httpclient.setCookieStore( cookieStore );

HttpStack httpStack = new HttpClientStack( httpclient );
RequestQueue requestQueue = Volley.newRequestQueue( context, httpStack  );

Der Vorteil gegenüber dem manuellen Einfügen von Cookies in die Header besteht darin, dass Sie eine tatsächliche Cookie-Verwaltung erhalten. Cookies in Ihrem Geschäft reagieren ordnungsgemäß auf HTTP-Steuerelemente, die ablaufen oder diese aktualisieren.

Ich bin noch einen Schritt weitergegangen und habe BasicCookieStore so deklassiert, dass ich meine Cookies automatisch auf Festplatte speichern kann.

JEDOCH! Wenn Sie nicht ältere Versionen von Android unterstützen müssen. Verwenden Sie einfach diese Methode:

// CookieStore is just an interface, you can implement it and do things like
// save the cookies to disk or what ever.
CookieStore cookieStore = new MyCookieStore();
CookieManager manager = new CookieManager( cookieStore, CookiePolicy.ACCEPT_ALL );
CookieHandler.setDefault( manager  );

// Optionally, you can just use the default CookieManager
CookieManager manager = new CookieManager();
CookieHandler.setDefault( manager  );

HttpURLConnection wird den CookieManager implizit davon abfragen. HttpUrlConnection ist auch performanter und ein bisschen sauberer, um IMO zu implementieren und damit zu arbeiten.

57
Adam

Der Standard-HTTP-Transportcode für Volley ist HttpUrlConnection. Wenn ich die Dokumentation richtig lese, müssen Sie sich für die Unterstützung des automatischen Sitzungscookies entscheiden:

CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);

Siehe auch Sollte HttpURLConnection mit CookieManager Session-Cookies automatisch behandeln?

20
CommonsWare

Jungs, versuchen Sie dies in der onCreate Methode Ihres AppController.Java 

  CookieHandler.setDefault(new CookieManager());

Ich hoffe, es spart den Entwicklern Zeit. Ich habe vier Stunden für das Debuggen und die Suche nach einer geeigneten Lösung verschwendet. 

10

@Rastio-Lösung funktioniert nicht, wenn mehrere 'Set-Cookie'-Header vorhanden sind. Ich habe den standardmäßigen CookieManager-Cookie-Store verpackt, und bevor ich ein Cookie hinzufügte, speicherte ich es in SharedPreferences mit Gson, um das Cookie zu serialisieren. 

Dies ist ein Beispiel für den Cookie-Store-Wrapper:

import Android.content.Context;
import Android.net.Uri;
import Android.util.Log;

import com.google.gson.Gson;

import Java.net.CookieManager;
import Java.net.CookieStore;
import Java.net.HttpCookie;
import Java.net.URI;
import Java.util.List;

/**
 * Class that implements CookieStore interface. This class saves to SharedPreferences the session
 * cookie.
 *
 * Created by lukas.
 */
public class PersistentCookieStore implements CookieStore {

    private CookieStore mStore;
    private Context mContext;
    private Gson mGson;

    public PersistentCookieStore(Context context) {
        // prevent context leaking by getting the application context
        mContext = context.getApplicationContext();
        mGson = new Gson();

        // get the default in memory store and if there is a cookie stored in shared preferences,
        // we added it to the cookie store
        mStore = new CookieManager().getCookieStore();
        String jsonSessionCookie = Prefs.getJsonSessionCookie(mContext);
        if (!jsonSessionCookie.equals(Prefs.DEFAULT_STRING)) {
            HttpCookie cookie = mGson.fromJson(jsonSessionCookie, HttpCookie.class);
            mStore.add(URI.create(cookie.getDomain()), cookie);
        }
    }

    @Override
    public void add(URI uri, HttpCookie cookie) {
        if (cookie.getName().equals("sessionid")) {
            // if the cookie that the cookie store attempt to add is a session cookie,
            // we remove the older cookie and save the new one in shared preferences
            remove(URI.create(cookie.getDomain()), cookie);
            Prefs.saveJsonSessionCookie(mContext, mGson.toJson(cookie));
        }

        mStore.add(URI.create(cookie.getDomain()), cookie);
    }

    @Override
    public List<HttpCookie> get(URI uri) {
        return mStore.get(uri);
    }

    @Override
    public List<HttpCookie> getCookies() {
        return mStore.getCookies();
    }

    @Override
    public List<URI> getURIs() {
        return mStore.getURIs();
    }

    @Override
    public boolean remove(URI uri, HttpCookie cookie) {
        return mStore.remove(uri, cookie);
    }

    @Override
    public boolean removeAll() {
        return mStore.removeAll();
    }
}

Dann verwenden Sie den Cookie-Store, den Sie im CookieManager festgelegt haben.

CookieManager cookieManager = new CookieManager(new PersistentCookieStore(mContext),
    CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
10
Lukas

Ich kenne den Beitrag und ein wenig alt, aber wir haben dieses kürzlich durchgeführte Problem durchlaufen. Wir müssen die Sitzung eines protokollierten Benutzers auf mehrere Server übertragen, und die serverseitige Lösung hat gefordert, dass der Client einen Wert über das Cookie bereitstellt. Eine Lösung, die wir fanden, bestand darin, dem RequestQueue-Objekt, dem Code-Snippet in der Methode getRequestQueue, einen Parameter hinzuzufügen, bevor die RequestQueue, die auf dem Link unten zu finden ist, instanziiert wird, und das Problem gelöst wird.

Besuchen Sie http://woxiangbo.iteye.com/blog/1769122

public class App extends Application {

    public static final String TAG = App.class.getSimpleName();

    private static App         mInstance;

    public static synchronized App getInstance() {
        return App.mInstance;
    }

    private RequestQueue mRequestQueue;

    public <T> void addToRequestQueue( final Request<T> req ) {
        req.setTag( App.TAG );
        this.getRequestQueue().add( req );
    }

    public <T> void addToRequestQueue( final Request<T> req, final String tag ) {
        req.setTag( TextUtils.isEmpty( tag ) ? App.TAG : tag );
        this.getRequestQueue().add( req );
    }

    public void cancelPendingRequests( final Object tag ) {
        if ( this.mRequestQueue != null ) {
            this.mRequestQueue.cancelAll( tag );
        }
    }

    public RequestQueue getRequestQueue() {

        if ( this.mRequestQueue == null ) {


            DefaultHttpClient mDefaultHttpClient = new DefaultHttpClient();

            final ClientConnectionManager mClientConnectionManager = mDefaultHttpClient.getConnectionManager();
            final HttpParams mHttpParams = mDefaultHttpClient.getParams();
            final ThreadSafeClientConnManager mThreadSafeClientConnManager = new ThreadSafeClientConnManager( mHttpParams, mClientConnectionManager.getSchemeRegistry() );

            mDefaultHttpClient = new DefaultHttpClient( mThreadSafeClientConnManager, mHttpParams );

            final HttpStack httpStack = new HttpClientStack( mDefaultHttpClient );

            this.mRequestQueue = Volley.newRequestQueue( this.getApplicationContext(), httpStack );
        }

        return this.mRequestQueue;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        App.mInstance = this;
    }
}

// Tokenwert setzen

ObjectRequest.setHeader( "Cookie", "JSESSIONID=" + tokenValueHere );
5
Anderson K

Lebkuchen-Android-Versionen:

es gibt eine weitere einfache Möglichkeit, die Cookies-Sitzung aufrechtzuerhalten. Sie können diese Zeile in einer Klasse hinzufügen, die mit der Klasse APPLICATION erweitert wird:

CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
2
asadullah

Verwenden Sie diese Methode, um Volley mit Cookies zu verwenden, um:

  1. Verwenden Sie nur sehr gut getesteten, unter Apache 2-Lizenz lizenzierten Code.
  2. So viele Anfragen gleichzeitig stellen}
  3. Stellen Sie sicher, dass Cookies auf dem Gerät bestehen bleiben
  4. Das Rad muss nicht neu erfunden werden

Mein Server verwendet Cookies zur Authentifizierung und natürlich wollte ich sicherstellen, dass Cookies auf dem Gerät erhalten bleiben. Meine Lösung war also die Verwendung von PersistentCookieStore und SerializableCookie Klassen aus Asynchronous Http Client für Android .

Um gleichzeitige Anforderungen zu aktivieren, ist ein Apache HttpClient v4.3-Port für Android erforderlich - einer, der mit dem System geliefert wird, ist veraltet. Mehr Infos hier . Ich benutze Gradle, also habe ich es importiert:

dependencies {
    compile group: 'org.Apache.httpcomponents' , name: 'httpclient-Android' , version: '4.3.3'
}

Funktion zum Abrufen von RequestQueue (in meiner Klasse, die Application erweitert):

private RequestQueue mRequestQueue;
private CloseableHttpClient httpClient;

...

public RequestQueue getRequestQueue() {
    if (mRequestQueue == null) {
        httpClient = HttpClients.custom()
            .setConnectionManager(new PoolingHttpClientConnectionManager())
            .setDefaultCookieStore(new PersistentCookieStore(getApplicationContext()))
            .build();
        mRequestQueue = Volley.newRequestQueue(getApplicationContext(), new HttpClientStack(httpClient));
    }
    return mRequestQueue;
}

So stelle ich eine Anfrage in die Warteschlange

public <T> void addToRequestQueue(Request<T> req, String tag) {
    req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
    getRequestQueue().add(req);
}

Das ist es! 

2
C0D3LIC1OU5

Wenn Sie bereits mit der Implementierung Ihrer Anwendung mithilfe der Loopj-Bibliothek begonnen haben, werden Sie feststellen, dass Sie die neue HttpClient-Instanz in Volley.newRequestQUeue () nicht verwenden können, da Sie verschiedene Fehler erhalten, wenn Sie Ihre vorherige Verbindung nicht schließen usw.

Fehler wie:

Java.lang.IllegalStateException: No wrapped connection

Invalid use of SingleClientConnManager: connection still allocated.

Jetzt dauert es manchmal Zeit, alle alten API-Aufrufe umzuformulieren und sie mit Volley umzuschreiben. Sie können jedoch Volley und Loopj gleichzeitig verwenden und einen Cookiestore zwischen diesen beiden teilen, bis Sie alles in Volleyball schreiben (verwenden Sie Volley anstelle von Loopj) ist viel besser :) ).

So können Sie HttpClient und CookieStore von loopj mit Volley teilen.

// For example you initialize loopj first
private static AsyncHttpClient client = new AsyncHttpClient();
sCookieStore = new PersistentCookieStore(getSomeContextHere());
client.setTimeout(DEFAULT_TIMEOUT);
client.setMaxConnections(12);
client.setCookieStore(sCookieStore);
client.setThreadPool(((ThreadPoolExecutor) Executors.newCachedThreadPool()));

public static RequestQueue getRequestQueue(){
    if(mRequestQueue == null){

    HttpClient httpclient = KkstrRestClient.getClient().getHttpClient();

    ((AbstractHttpClient) httpclient).setCookieStore( ApplicationController.getCookieStore() );

    HttpStack httpStack = new HttpClientStack(httpclient);

    mRequestQueue = Volley.newRequestQueue(getContext(), httpStack);
    }

    return mRequestQueue;
}

Das ist mir passiert, wir begannen mit loopj. Nach 50.000 Zeilen Code und Entdeckung, dass Loopj nicht immer wie erwartet funktioniert, haben wir uns entschieden, zu Volley zu wechseln.

1
Drag0

In meinem Projekt wird CookieManager als Android.webkit.CookieManager..__ aufgelöst. Ich muss den Handler wie folgt einstellen, damit Volley Cookies automatisch behandelt.

CookieManager cookieManager = neues Java.net.CookieManager (); CookieHandler.setDefault (cookieManager);

0
starshine wang

Die Antwort von @CommonsWare würde ich verwenden. Es sieht jedoch so aus, als hätte KitKat einige Fehler , wenn dies erledigt ist (Wenn Sie eine CookieManager mit benutzerdefinierten CookieStore Datei erstellen, die Sie benötigen, wenn Sie dauerhafte Cookies wünschen) Unabhängig von der Implementierung des verwendeten CookieStore, würde Volley ein NullpointerException werfen. Ich musste mein eigenes CookieHandler... erstellen, wenn es hilfreich ist.

public class MyCookieHandler extends CookieHandler {

private static final String VERSION_ZERO_HEADER = "Set-cookie";

private static final String VERSION_ONE_HEADER = "Set-cookie2";
private static final String COOKIE_HEADER = "Cookie";

private static final String COOKIE_FILE = "Cookies";
private Map<String, Map<String, HttpCookie>> urisMap;

private Context context;

public MyCookieHandler(Context context) {

    this.context = context;
    loadCookies();

}

@SuppressWarnings("unchecked")
private void loadCookies() {
    File file = context.getFileStreamPath(COOKIE_FILE);
    if (file.exists())
        try {

            FileInputStream fis = context.openFileInput(COOKIE_FILE);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    fis));
            String line = br.readLine();
            StringBuilder sb = new StringBuilder();
            while (line != null) {
                sb.append(line);
                line = br.readLine();
            }
            Log.d("MyCookieHandler.loadCookies", sb.toString());
            JSONObject jsonuris = new JSONObject(sb.toString());
            urisMap = new HashMap<String, Map<String, HttpCookie>>();
            Iterator<String> jsonurisiter = jsonuris.keys();

            while (jsonurisiter.hasNext()) {
                String prop = jsonurisiter.next();
                HashMap<String, HttpCookie> cookiesMap = new HashMap<String, HttpCookie>();
                JSONObject jsoncookies = jsonuris.getJSONObject(prop);
                Iterator<String> jsoncookiesiter = jsoncookies.keys();
                while (jsoncookiesiter.hasNext()) {
                    String pprop = jsoncookiesiter.next();
                    cookiesMap.put(pprop,
                            jsonToCookie(jsoncookies.getJSONObject(pprop)));
                }
                urisMap.put(prop, cookiesMap);

            }

        } catch (Exception e) {

            e.printStackTrace();
        }
    else {
        urisMap = new HashMap<String, Map<String, HttpCookie>>();
    }
}

@Override
public Map<String, List<String>> get(URI arg0,
        Map<String, List<String>> arg1) throws IOException {
    Log.d("MyCookieHandler.get",
            "getting Cookies for domain: " + arg0.getHost());
    Map<String, HttpCookie> cookies = urisMap.get(arg0.getHost());
    if (cookies != null)
        for (Entry<String, HttpCookie> cookie : cookies.entrySet()) {
            if (cookie.getValue().hasExpired()) {
                cookies.remove(cookie.getKey());
            }
        }

    if (cookies == null || cookies.isEmpty()) {
        Log.d("MyCookieHandler.get", "======");
        return Collections.emptyMap();
    }
    Log.d("MyCookieHandler.get",
            "Cookie : " + TextUtils.join("; ", cookies.values()));
    Log.d("MyCookieHandler.get", "======");
    return Collections.singletonMap(COOKIE_HEADER, Collections
            .singletonList(TextUtils.join("; ", cookies.values())));
}

@Override
public void put(URI uri, Map<String, List<String>> arg1) throws IOException {
    Map<String, HttpCookie> cookies = parseCookies(arg1);
    Log.d("MyCookieHandler.put",
            "saving Cookies for domain: " + uri.getHost());

    addCookies(uri, cookies);
    Log.d("MyCookieHandler.put",
            "Cookie : " + TextUtils.join("; ", cookies.values()));
    Log.d("MyCookieHandler.put", "======");

}

private void addCookies(URI uri, Map<String, HttpCookie> cookies) {
    if (!cookies.isEmpty()) {
        if (urisMap.get(uri.getHost()) == null) {
            urisMap.put(uri.getHost(), cookies);
        } else {
            urisMap.get(uri.getHost()).putAll(cookies);
        }
        saveCookies();
    }
}

private void saveCookies() {
    try {
        FileOutputStream fos = context.openFileOutput(COOKIE_FILE,
                Context.MODE_PRIVATE);

        JSONObject jsonuris = new JSONObject();
        for (Entry<String, Map<String, HttpCookie>> uris : urisMap
                .entrySet()) {
            JSONObject jsoncookies = new JSONObject();
            for (Entry<String, HttpCookie> savedCookies : uris.getValue()
                    .entrySet()) {
                jsoncookies.put(savedCookies.getKey(),
                        cookieToJson(savedCookies.getValue()));
            }
            jsonuris.put(uris.getKey(), jsoncookies);
        }
        fos.write(jsonuris.toString().getBytes());
        fos.close();
        Log.d("MyCookieHandler.addCookies", jsonuris.toString());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static JSONObject cookieToJson(HttpCookie cookie) {
    JSONObject jsoncookie = new JSONObject();
    try {
        jsoncookie.put("discard", cookie.getDiscard());
        jsoncookie.put("maxAge", cookie.getMaxAge());
        jsoncookie.put("secure", cookie.getSecure());
        jsoncookie.put("version", cookie.getVersion());
        jsoncookie.put("comment", cookie.getComment());
        jsoncookie.put("commentURL", cookie.getCommentURL());
        jsoncookie.put("domain", cookie.getDomain());
        jsoncookie.put("name", cookie.getName());
        jsoncookie.put("path", cookie.getPath());
        jsoncookie.put("portlist", cookie.getPortlist());
        jsoncookie.put("value", cookie.getValue());

    } catch (JSONException e) {

        e.printStackTrace();
    }

    return jsoncookie;
}

private static HttpCookie jsonToCookie(JSONObject jsonObject) {
    HttpCookie httpCookie;
    try {
        httpCookie = new HttpCookie(jsonObject.getString("name"),
                jsonObject.getString("value"));
        if (jsonObject.has("comment"))
            httpCookie.setComment(jsonObject.getString("comment"));
        if (jsonObject.has("commentURL"))
            httpCookie.setCommentURL(jsonObject.getString("commentURL"));
        if (jsonObject.has("discard"))
            httpCookie.setDiscard(jsonObject.getBoolean("discard"));
        if (jsonObject.has("domain"))
            httpCookie.setDomain(jsonObject.getString("domain"));
        if (jsonObject.has("maxAge"))
            httpCookie.setMaxAge(jsonObject.getLong("maxAge"));
        if (jsonObject.has("path"))
            httpCookie.setPath(jsonObject.getString("path"));
        if (jsonObject.has("portlist"))
            httpCookie.setPortlist(jsonObject.getString("portlist"));
        if (jsonObject.has("secure"))
            httpCookie.setSecure(jsonObject.getBoolean("secure"));
        if (jsonObject.has("version"))
            httpCookie.setVersion(jsonObject.getInt("version"));
        return httpCookie;
    } catch (JSONException e) {

        e.printStackTrace();
    }
    return null;

}

private Map<String, HttpCookie> parseCookies(Map<String, List<String>> map) {
    Map<String, HttpCookie> response = new HashMap<String, HttpCookie>();

    for (Entry<String, List<String>> e : map.entrySet()) {
        String key = e.getKey();
        if (key != null
                && (key.equalsIgnoreCase(VERSION_ONE_HEADER) || key
                        .equalsIgnoreCase(VERSION_ZERO_HEADER))) {
            for (String cookie : e.getValue()) {
                try {
                    for (HttpCookie htpc : HttpCookie.parse(cookie)) {
                        response.put(htpc.getName(), htpc);
                    }
                } catch (Exception e1) {

                    Log.e("MyCookieHandler.parseCookies",
                            "Error parsing cookies", e1);
                }
            }

        }
    }
    return response;

}
}

Diese Antwort wurde nicht gründlich getestet. Ich habe JSON verwendet, um Cookies zu serialisieren, denn diese Klasse implementiert Serializable nicht und ist endgültig.

0
caeus