changed stream based json deserialization to reader based json deserialization

updated library version
This commit is contained in:
Mariotaku Lee 2016-02-16 13:18:51 +08:00
parent 1969016700
commit 7c3d02c986
9 changed files with 195 additions and 57 deletions

View File

@ -43,7 +43,7 @@ dependencies {
compile 'com.android.support:support-v4:23.1.1'
compile 'com.bluelinelabs:logansquare:1.3.4'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.github.mariotaku.RestFu:library:0.9.19'
compile 'com.github.mariotaku.RestFu:library:0.9.20'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.2'
compile 'com.github.mariotaku.ObjectCursor:core:0.9.3'
compile fileTree(dir: 'libs', include: ['*.jar'])

View File

@ -23,7 +23,7 @@ android {
applicationId "org.mariotaku.twidere"
minSdkVersion 14
targetSdkVersion 23
versionCode 144
versionCode 145
versionName "3.0.5 (snapshot)"
multiDexEnabled true
@ -107,8 +107,8 @@ dependencies {
compile 'com.soundcloud.android:android-crop:1.0.1@aar'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.2'
compile 'com.github.mariotaku:PickNCrop:0.9.3'
compile 'com.github.mariotaku.RestFu:library:0.9.19'
compile 'com.github.mariotaku.RestFu:okhttp3:0.9.19'
compile 'com.github.mariotaku.RestFu:library:0.9.20'
compile 'com.github.mariotaku.RestFu:okhttp3:0.9.20'
compile 'com.squareup.okhttp3:okhttp:3.1.2'
compile 'com.lnikkila:extendedtouchview:0.1.0'
compile 'com.google.dagger:dagger:2.0.2'

View File

@ -0,0 +1,24 @@
package org.mariotaku.twidere.util;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.junit.Test;
import org.mariotaku.twidere.api.twitter.model.CursorTimestampResponse;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
import org.mariotaku.twidere.api.twitter.model.Status;
import java.util.List;
import static org.junit.Assert.assertEquals;
/**
* Created by mariotaku on 16/2/15.
*/
public class TwidereTypeUtilsTest {
@Test
public void testGetSimpleName() throws Exception {
assertEquals("CursorTimestampResponse", TwidereTypeUtils.toSimpleName(CursorTimestampResponse.class));
assertEquals("ResponseList<Status>", TwidereTypeUtils.toSimpleName(TypeUtils.parameterize(ResponseList.class, Status.class)));
assertEquals("List<List<Object>>", TwidereTypeUtils.toSimpleName(TypeUtils.parameterize(List.class, TypeUtils.parameterize(List.class, Object.class))));
}
}

View File

@ -21,7 +21,10 @@ package org.mariotaku.twidere.api.twitter.util;
import android.support.annotation.NonNull;
import android.support.v4.util.SimpleArrayMap;
import android.util.Log;
import android.util.TimingLogger;
import com.bluelinelabs.logansquare.JsonMapper;
import com.bluelinelabs.logansquare.LoganSquare;
import com.bluelinelabs.logansquare.ParameterizedType;
import com.bluelinelabs.logansquare.ParameterizedTypeAccessor;
@ -30,14 +33,16 @@ import com.fasterxml.jackson.core.JsonParseException;
import org.mariotaku.restfu.RestConverter;
import org.mariotaku.restfu.http.HttpResponse;
import org.mariotaku.restfu.http.mime.Body;
import org.mariotaku.restfu.http.mime.SimpleBody;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.auth.OAuthToken;
import org.mariotaku.twidere.api.twitter.model.ResponseCode;
import org.mariotaku.twidere.api.twitter.model.TwitterResponse;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.util.TwidereTypeUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Type;
/**
@ -57,7 +62,9 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
try {
final Body body = resp.getBody();
if (body == null) return new TwitterException(resp);
final TwitterException parse = LoganSquare.parse(body.stream(), TwitterException.class);
final JsonMapper<TwitterException> mapper = LoganSquare.mapperFor(TwitterException.class);
final Reader reader = SimpleBody.reader(body);
final TwitterException parse = mapper.parse(LoganSquare.JSON_FACTORY.createParser(reader));
if (parse != null) return parse;
return new TwitterException(resp);
} catch (JsonParseException e) {
@ -68,11 +75,22 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
}
@NonNull
private static <T> T parseOrThrow(InputStream stream, Type type)
private static <T> T parseOrThrow(Body body, Type type)
throws IOException, TwitterException, RestConverter.ConvertException {
try {
if (BuildConfig.DEBUG) {
Log.d("TwitterConverter", TwidereTypeUtils.toSimpleName(type) + " <---");
}
final ParameterizedType<T> parameterizedType = ParameterizedTypeAccessor.create(type);
final T parsed = LoganSquare.parse(stream, parameterizedType);
final JsonMapper<T> mapper = LoganSquare.mapperFor(parameterizedType);
if (BuildConfig.DEBUG) {
Log.d("TwitterConverter", TwidereTypeUtils.toSimpleName(type) + " ---> " + TwidereTypeUtils.toSimpleName(mapper.getClass()));
}
final Reader reader = SimpleBody.reader(body);
final T parsed = mapper.parse(LoganSquare.JSON_FACTORY.createParser(reader));
if (BuildConfig.DEBUG) {
Log.d("TwitterConverter", TwidereTypeUtils.toSimpleName(type) + " Finished");
}
if (parsed == null) {
throw new TwitterException("Empty data");
}
@ -82,12 +100,6 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
}
}
private static void checkResponse(Type type, Object object, HttpResponse response) throws TwitterException {
if (User.class == type) {
if (object == null) throw new TwitterException("User is null");
}
}
@Override
public RestConverter<HttpResponse, ?, TwitterException> forResponse(Type type) {
RestConverter<HttpResponse, ?, TwitterException> converter = sResponseConverters.get(type);
@ -121,13 +133,18 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
@Override
public Object convert(HttpResponse httpResponse) throws IOException, ConvertException, TwitterException {
final TimingLogger logger = new TimingLogger("TwitterConverter", TwidereTypeUtils.toSimpleName(type));
logger.addSplit("Status code: " + httpResponse.getStatus());
final Body body = httpResponse.getBody();
final InputStream stream = body.stream();
final Object object = parseOrThrow(stream, type);
checkResponse(type, object, httpResponse);
logger.addSplit("Start parsing");
final Object object = parseOrThrow(body, type);
logger.addSplit("End parsing");
if (object instanceof TwitterResponse) {
((TwitterResponse) object).processResponseHeader(httpResponse);
}
if (BuildConfig.DEBUG) {
logger.dumpToLog();
}
return object;
}
}

View File

@ -2,7 +2,6 @@ package org.mariotaku.twidere.fragment;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.AsyncTask;
@ -10,6 +9,8 @@ import android.os.Bundle;
import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.text.Selection;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.ScrollingMovementMethod;
@ -20,7 +21,12 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import org.mariotaku.restfu.RestAPIFactory;
import org.mariotaku.restfu.annotation.method.GET;
import org.mariotaku.restfu.http.Endpoint;
import org.mariotaku.restfu.http.HttpRequest;
import org.mariotaku.restfu.http.HttpResponse;
import org.mariotaku.restfu.http.RestHttpClient;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
@ -30,10 +36,13 @@ import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.dagger.DependencyHolder;
import org.mariotaku.twidere.util.net.TwidereDns;
import org.xbill.DNS.ResolverConfig;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.net.UnknownHostException;
@ -78,18 +87,27 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
private void appendMessage(LogText message) {
SpannableString coloredText = SpannableString.valueOf(message.message);
switch (message.state) {
case LogText.State.GOOD: {
coloredText.setSpan(new ForegroundColorSpan(Color.GREEN), 0, coloredText.length(),
case LogText.State.OK: {
coloredText.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getActivity(),
R.color.material_light_green)), 0, coloredText.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
}
case LogText.State.BAD: {
coloredText.setSpan(new ForegroundColorSpan(Color.RED), 0, coloredText.length(),
case LogText.State.ERROR: {
coloredText.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getActivity(),
R.color.material_red)), 0, coloredText.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
}
case LogText.State.WARNING: {
coloredText.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getActivity(),
R.color.material_amber)), 0, coloredText.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
}
}
mLogTextView.append(coloredText);
Selection.setSelection(mLogTextView.getEditableText(), mLogTextView.length());
}
static class DiagnosticsTask extends AsyncTask<Object, LogText, Object> {
@ -108,21 +126,10 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
@Override
protected Object doInBackground(Object... params) {
publishProgress(new LogText("Build information: "));
publishProgress(new LogText("version_code: " + BuildConfig.VERSION_CODE), LogText.LINEBREAK);
publishProgress(new LogText("version_name: " + BuildConfig.VERSION_NAME), LogText.LINEBREAK);
publishProgress(new LogText("flavor: " + BuildConfig.FLAVOR), LogText.LINEBREAK);
publishProgress(new LogText("debug: " + BuildConfig.DEBUG), LogText.LINEBREAK);
publishProgress(LogText.LINEBREAK);
publishProgress(new LogText("Basic system information: "));
publishProgress(new LogText(String.valueOf(mContext.getResources().getConfiguration())));
publishProgress(new LogText("**** NOTICE ****", LogText.State.WARNING));
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
publishProgress(new LogText("Active network info: "));
publishProgress(new LogText(String.valueOf(mConnectivityManager.getActiveNetworkInfo())));
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
publishProgress(new LogText("**** NOTICE ****"));
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
publishProgress(new LogText("Text below may have personal information, BE CAREFUL TO MAKE IT PUBLIC"));
publishProgress(new LogText("Text below may have personal information, BE CAREFUL TO MAKE IT PUBLIC",
LogText.State.WARNING));
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
DependencyHolder holder = DependencyHolder.get(mContext);
final TwidereDns dns = holder.getDns();
@ -164,12 +171,47 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
testDns(dns, host);
testNativeLookup(host);
} else {
publishProgress(new LogText("API URL format is invalid", LogText.State.BAD));
publishProgress(new LogText("API URL format is invalid", LogText.State.ERROR));
publishProgress(LogText.LINEBREAK);
}
publishProgress(LogText.LINEBREAK);
publishProgress(new LogText("Testing Network connectivity"));
publishProgress(LogText.LINEBREAK);
final String baseUrl = TwitterAPIFactory.getApiBaseUrl(credentials.api_url_format, "api");
RestHttpClient client = RestAPIFactory.getRestClient(twitter).getRestClient();
HttpResponse response = null;
try {
publishProgress(new LogText("Connecting to " + baseUrl + "..."));
HttpRequest.Builder builder = new HttpRequest.Builder();
builder.method(GET.METHOD);
builder.url(baseUrl);
final long start = SystemClock.uptimeMillis();
response = client.newCall(builder.build()).execute();
publishProgress(new LogText(String.format(" OK (%d ms)", SystemClock.uptimeMillis()
- start), LogText.State.OK));
} catch (IOException e) {
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
}
publishProgress(LogText.LINEBREAK);
try {
if (response != null) {
publishProgress(new LogText("Reading response..."));
final long start = SystemClock.uptimeMillis();
final CountOutputStream os = new CountOutputStream();
response.getBody().writeTo(os);
publishProgress(new LogText(String.format(" %d bytes (%d ms)", os.getTotal(),
SystemClock.uptimeMillis() - start), LogText.State.OK));
}
} catch (IOException e) {
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
} finally {
Utils.closeSilently(response);
}
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
publishProgress(new LogText("Testing API functionality"));
publishProgress(LogText.LINEBREAK);
testTwitter("verify_credentials", twitter, new TwitterTest() {
@ -202,6 +244,20 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
testNativeLookup("twitter.com");
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
publishProgress(new LogText("Build information: "));
publishProgress(new LogText("version_code: " + BuildConfig.VERSION_CODE), LogText.LINEBREAK);
publishProgress(new LogText("version_name: " + BuildConfig.VERSION_NAME), LogText.LINEBREAK);
publishProgress(new LogText("flavor: " + BuildConfig.FLAVOR), LogText.LINEBREAK);
publishProgress(new LogText("debug: " + BuildConfig.DEBUG), LogText.LINEBREAK);
publishProgress(LogText.LINEBREAK);
publishProgress(new LogText("Basic system information: "));
publishProgress(new LogText(String.valueOf(mContext.getResources().getConfiguration())));
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
publishProgress(new LogText("Active network info: "));
publishProgress(new LogText(String.valueOf(mConnectivityManager.getActiveNetworkInfo())));
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
publishProgress(new LogText("Done. You can send this log to me, and I'll contact you to solve related issue."));
return null;
}
@ -212,9 +268,9 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
final long start = SystemClock.uptimeMillis();
publishProgress(new LogText(String.valueOf(dns.lookupResolver(host))));
publishProgress(new LogText(String.format(" OK (%d ms)", SystemClock.uptimeMillis()
- start), LogText.State.GOOD));
- start), LogText.State.OK));
} catch (UnknownHostException e) {
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.BAD));
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
}
publishProgress(LogText.LINEBREAK);
}
@ -225,9 +281,9 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
final long start = SystemClock.uptimeMillis();
publishProgress(new LogText(Arrays.toString(InetAddress.getAllByName(host))));
publishProgress(new LogText(String.format(" OK (%d ms)", SystemClock.uptimeMillis()
- start), LogText.State.GOOD));
- start), LogText.State.OK));
} catch (UnknownHostException e) {
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.BAD));
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
}
publishProgress(LogText.LINEBREAK);
}
@ -238,9 +294,9 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
final long start = SystemClock.uptimeMillis();
test.execute(twitter);
publishProgress(new LogText(String.format("OK (%d ms)", SystemClock.uptimeMillis()
- start), LogText.State.GOOD));
- start), LogText.State.OK));
} catch (TwitterException e) {
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.BAD));
publishProgress(new LogText("ERROR: " + e.getMessage(), LogText.State.ERROR));
}
publishProgress(LogText.LINEBREAK);
}
@ -311,12 +367,25 @@ public class NetworkDiagnosticsFragment extends BaseFragment {
this.message = message;
}
@IntDef({State.DEFAULT, State.GOOD, State.BAD})
@IntDef({State.DEFAULT, State.OK, State.ERROR, State.WARNING})
@interface State {
int DEFAULT = 0;
int GOOD = 1;
int BAD = 2;
int OK = 1;
int ERROR = 2;
int WARNING = 3;
}
}
private static class CountOutputStream extends OutputStream {
private long total;
public long getTotal() {
return total;
}
@Override
public void write(int oneByte) throws IOException {
total++;
}
}
}

View File

@ -7,7 +7,7 @@ import android.text.TextUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.restfu.http.RestHttpClient;
import org.mariotaku.restfu.okhttp.OkHttpRestClient;
import org.mariotaku.restfu.okhttp3.OkHttpRestClient;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.util.dagger.DependencyHolder;
import org.mariotaku.twidere.util.net.TwidereProxySelector;
@ -101,8 +101,7 @@ public class HttpClientFactory implements Constants {
}
public static void reloadConnectivitySettings(Context context) {
DependencyHolder holder = DependencyHolder.get(context);
holder.getConnectionPoll().evictAll();
final DependencyHolder holder = DependencyHolder.get(context);
final RestHttpClient client = holder.getRestHttpClient();
if (client instanceof OkHttpRestClient) {
final OkHttpClient.Builder builder = new OkHttpClient.Builder();

View File

@ -40,7 +40,7 @@ import org.mariotaku.restfu.http.MultiValueMap;
import org.mariotaku.restfu.http.RestHttpClient;
import org.mariotaku.restfu.http.mime.FormBody;
import org.mariotaku.restfu.http.mime.SimpleBody;
import org.mariotaku.restfu.okhttp.OkHttpRestClient;
import org.mariotaku.restfu.okhttp3.OkHttpRestClient;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.TwitterOAuth;

View File

@ -0,0 +1,33 @@
package org.mariotaku.twidere.util;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Created by mariotaku on 16/2/15.
*/
public class TwidereTypeUtils {
public static String toSimpleName(Type type) {
final StringBuilder sb = new StringBuilder();
buildSimpleName(type, sb);
return sb.toString();
}
private static void buildSimpleName(Type type, StringBuilder sb) {
if (type instanceof Class) {
sb.append(((Class) type).getSimpleName());
} else if (type instanceof ParameterizedType) {
buildSimpleName(((ParameterizedType) type).getRawType(), sb);
sb.append("<");
final Type[] args = ((ParameterizedType) type).getActualTypeArguments();
for (int i = 0; i < args.length; i++) {
if (i != 0) {
sb.append(",");
}
buildSimpleName(args[i], sb);
}
sb.append(">");
}
}
}

View File

@ -43,7 +43,6 @@ import org.mariotaku.twidere.model.ConsumerKeyType;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.util.dagger.DependencyHolder;
import org.mariotaku.twidere.util.net.TwidereDns;
import java.io.IOException;
import java.util.HashMap;
@ -143,7 +142,7 @@ public class TwitterAPIFactory implements TwidereConstants {
factory.setConstantPool(sConstantPoll);
factory.setRestConverterFactory(new TwitterConverterFactory());
factory.setHttpRequestFactory(new TwidereHttpRequestFactory(userAgent));
factory.setExceptionFactory(new TwidereExceptionFactory(holder.getDns()));
factory.setExceptionFactory(new TwidereExceptionFactory());
return factory.build(cls);
}
@ -440,10 +439,7 @@ public class TwitterAPIFactory implements TwidereConstants {
public static class TwidereExceptionFactory implements ExceptionFactory<TwitterException> {
private final TwidereDns dns;
TwidereExceptionFactory(TwidereDns dns) {
this.dns = dns;
TwidereExceptionFactory() {
}
@Override