Skip to content
This repository was archived by the owner on Jun 18, 2020. It is now read-only.

Commit 7f2314a

Browse files
authored
Deprecate XingApi's resource function (#245)
* Completely remove XingApi's resource function. Also removed factories and made all resource's constructors public. * Bump version, add changelog
1 parent bf61909 commit 7f2314a

20 files changed

+45
-288
lines changed

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
language: android
2+
dist: trusty
23

34
android:
45
components:
@@ -16,8 +17,6 @@ script:
1617
- ./gradlew clean check --stacktrace
1718

1819
before_install:
19-
- yes | sdkmanager "platforms;android-26"
20-
- yes | sdkmanager "platforms;android-28"
2120
- export TZ=Europe/Berlin
2221

2322
after_success:

CHANGELOG.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
Change Log
22
==========
33

4-
Version 3.0.7 *2019-01-31*
4+
## Version 3.1.0 *(2019-07-30)*
5+
6+
### Breaking‼️:
7+
8+
* [Remove XingApi's resource function](https://github.com/xing/xing-android-sdk/pull/245)
9+
* See `GETTING_STARTED_ANDROID` for usage. The reasons for this change are:
10+
* `XingApi` is a dependency of any `Resource`, therefore it doesn't make sense that the former provides or holds a
11+
Resource in any way.
12+
* `XingApi` also used to hold a cache of resources, this could potentially cause problems if an implementation would
13+
contain any mutable state inside, as it would be propagated to further calls to the `resource` function.
14+
* Finally, this function used to sometimes rely on reflection, which is not mentioned anywhere and leads to runtime
15+
crashes when the target implementation Proguard's strips out the resources.
16+
17+
## Version 3.0.7 *(2019-01-31)*
518

619
* Update moshi to 1.8.0
720
* Update minSdk to 21
@@ -10,18 +23,15 @@ Version 3.0.7 *2019-01-31*
1023
* Update build tools to 28.0.3
1124
* Update kotlin version to 1.3.20
1225

13-
Version 3.0.6 *2019-01-10*
14-
----------------------------
26+
## Version 3.0.6 *(2019-01-10)*
1527

1628
* [Allow setting a hostname verifier](https://github.com/xing/xing-android-sdk/pull/242)
1729

18-
Version 2.0.1 *(2016-11-16)*
19-
----------------------------
30+
## Version 2.0.1 *(2016-11-16)*
2031

2132
* Fix internal parsing mechanism to work with moshi 1.2.0 and higher.
2233
* Rename `XingApi#converter()` to `XingApi#moshi()`
2334

24-
Version 2.0.0 *(2016-09-27)*
25-
----------------------------
35+
## Version 2.0.0 *(2016-09-27)*
2636

2737
* Initial Release of the XING API Client Version 2.0.0

GETTING_STARTED_ANDROID.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ data. For example, let's assume that you need to access the users profile data:
5151
```java
5252

5353
// First you need to select the resource you want to access.
54-
UserProfileResource resource = xingApi.resource(UserProfileResource.class);
54+
UserProfileResource resource = new UserProfileResource(xingApi);
5555

5656
// Get the spec for the user profile request.
5757
CallSpec<XingUser, HttpError> spec = resource.getOwnProfile();

api-client-android-sample/src/main/java/com/xing/api/sample/ui/ProfileActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ protected XingUser doInBackground(Activity... params) {
182182
.accessToken(Prefs.getInstance(ProfileActivity.this).getOauthToken())
183183
.accessSecret(Prefs.getInstance(ProfileActivity.this).getOauthSecret())
184184
.build();
185-
UserProfilesResource profilesResource = api.resource(UserProfilesResource.class);
185+
UserProfilesResource profilesResource = new UserProfilesResource(api);
186186
Response<XingUser, HttpError> response = null;
187187
try {
188188
response = profilesResource.getOwnProfile().execute();

api-client/src/main/java/com/xing/api/Resource.java

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,28 +69,4 @@ protected static Type first(Type searchFor, String... roots) {
6969
return Converter.first(searchFor, roots);
7070
}
7171

72-
/** Allows {@link Resource} creation via a non reflective api. */
73-
public abstract static class Factory {
74-
private final Class<? extends Resource> resourceCls;
75-
76-
public Factory(Class<? extends Resource> resourceCls) {
77-
this.resourceCls = resourceCls;
78-
}
79-
80-
/**
81-
* Attempts to create a resource of {@code cls}. This returns the resource if one was created, or {@code null} if
82-
* this factory isn't capable of creating such a resource.
83-
*/
84-
final Resource create(Class<? extends Resource> cls, XingApi api) {
85-
return cls == resourceCls ? create(api) : null;
86-
}
87-
88-
/**
89-
* Creates a {@linkplain Resource resource} instance of the class which <strong>this</strong> factory is attached
90-
* to.
91-
*
92-
* <p>Implementations should <b>not</b> use {@link XingApi#resource(Class)} since it may result in an infinite loop.
93-
*/
94-
public abstract Resource create(XingApi api);
95-
}
9672
}

api-client/src/main/java/com/xing/api/XingApi.java

Lines changed: 4 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.serjltt.moshi.adapters.FallbackEnum;
1919
import com.serjltt.moshi.adapters.FallbackOnNull;
2020
import com.squareup.moshi.Moshi;
21-
import com.xing.api.Resource.Factory;
2221
import com.xing.api.internal.Experimental;
2322
import com.xing.api.internal.json.BirthDateJsonAdapter;
2423
import com.xing.api.internal.json.ContactPathJsonAdapter;
@@ -28,26 +27,9 @@
2827
import com.xing.api.internal.json.SafeCalendarJsonAdapter;
2928
import com.xing.api.internal.json.SafeEnumJsonAdapter;
3029
import com.xing.api.internal.json.TimeZoneJsonAdapter;
31-
import com.xing.api.resources.BookmarksResource;
32-
import com.xing.api.resources.ContactsResource;
33-
import com.xing.api.resources.GroupsResource;
34-
import com.xing.api.resources.JobsResource;
35-
import com.xing.api.resources.MessagesResource;
36-
import com.xing.api.resources.MiscellaneousResource;
37-
import com.xing.api.resources.ProfileEditingResource;
38-
import com.xing.api.resources.ProfileVisitsResource;
39-
import com.xing.api.resources.RecommendationsResource;
40-
import com.xing.api.resources.UserProfilesResource;
41-
42-
import java.lang.reflect.Constructor;
43-
import java.lang.reflect.Modifier;
44-
import java.util.ArrayList;
45-
import java.util.LinkedHashMap;
46-
import java.util.LinkedHashSet;
30+
4731
import java.util.LinkedList;
4832
import java.util.List;
49-
import java.util.Map;
50-
import java.util.Set;
5133
import java.util.concurrent.Executor;
5234

5335
import okhttp3.HttpUrl;
@@ -58,16 +40,7 @@
5840
import static com.xing.api.Utils.stateNull;
5941

6042
/**
61-
* Main access point for the XING API. Creates and holds instances of {@linkplain Response resources} that provide access
62-
* points and response/error handling for XING APIs.
63-
* <p>
64-
* Usage:
65-
* <pre>{@code
66-
* // Will instantiate ContactsResource.
67-
* ContactsResource resource = xingApi.resource(ContactsResource.class);
68-
* }</pre>
69-
* <p>
70-
* Two states of XingApi are supported:
43+
* Main access point for the XING API. Two states of XingApi are supported:
7144
* <dl>
7245
* <li>Logged in - Requires a user's access token and token secret (See {@linkplain XingApi.Builder}.)</li>
7346
* <li>Logged out - See {@linkplain Builder#loggedOut()}</li>
@@ -76,73 +49,21 @@
7649
* @since 2.0.0
7750
*/
7851
public final class XingApi {
79-
/** A list of built in factories for resources shipped with the library. */
80-
private static final List<Resource.Factory> BUILT_IN_FACTORIES = new ArrayList<>();
81-
82-
static {
83-
BUILT_IN_FACTORIES.add(BookmarksResource.FACTORY);
84-
BUILT_IN_FACTORIES.add(ContactsResource.FACTORY);
85-
BUILT_IN_FACTORIES.add(GroupsResource.FACTORY);
86-
BUILT_IN_FACTORIES.add(JobsResource.FACTORY);
87-
BUILT_IN_FACTORIES.add(MessagesResource.FACTORY);
88-
BUILT_IN_FACTORIES.add(MiscellaneousResource.FACTORY);
89-
BUILT_IN_FACTORIES.add(ProfileEditingResource.FACTORY);
90-
BUILT_IN_FACTORIES.add(ProfileVisitsResource.FACTORY);
91-
BUILT_IN_FACTORIES.add(RecommendationsResource.FACTORY);
92-
BUILT_IN_FACTORIES.add(UserProfilesResource.FACTORY);
93-
}
94-
95-
@SuppressWarnings("CollectionWithoutInitialCapacity")
96-
private final Map<Class<? extends Resource>, Resource> resourcesCache = new LinkedHashMap<>();
9752
private final List<AuthErrorCallback> authErrorCallbacks = new LinkedList<>();
9853

99-
private final Set<Resource.Factory> resourceFactories;
10054
private final OkHttpClient client;
10155
private final HttpUrl apiEndpoint;
10256
private final Converter converter;
10357
private final CallbackAdapter callbackAdapter;
10458
private final Executor callbackExecutor;
10559

10660
XingApi(OkHttpClient client, HttpUrl apiEndpoint, Converter converter, CallbackAdapter callbackAdapter,
107-
Executor callbackExecutor, List<Resource.Factory> resourceFactories) {
61+
Executor callbackExecutor) {
10862
this.client = client;
10963
this.apiEndpoint = apiEndpoint;
11064
this.converter = converter;
11165
this.callbackAdapter = callbackAdapter;
11266
this.callbackExecutor = callbackExecutor;
113-
114-
/* Initialise the factories and add custom ones. */
115-
this.resourceFactories = new LinkedHashSet<>(resourceFactories);
116-
this.resourceFactories.addAll(BUILT_IN_FACTORIES);
117-
}
118-
119-
/** Return a {@link Resource} instance specified by the provided class. */
120-
@SuppressWarnings("unchecked")
121-
public <T extends Resource> T resource(Class<T> resource) {
122-
Resource res = resourcesCache.get(checkNotNull(resource, "resource == null"));
123-
if (res == null) {
124-
// First try to create the resource via a factory
125-
for (Resource.Factory factory : resourceFactories) {
126-
res = factory.create(resource, this);
127-
128-
if (res != null) { // yay!
129-
resourcesCache.put(resource, res);
130-
return (T) res;
131-
}
132-
}
133-
134-
// Fallback to the reflection path
135-
checkResourceClassDeclaration(resource);
136-
try {
137-
Constructor<? extends Resource> constructor = resource.getDeclaredConstructor(XingApi.class);
138-
constructor.setAccessible(true);
139-
res = constructor.newInstance(this);
140-
resourcesCache.put(resource, res);
141-
} catch (Exception ex) {
142-
throw new IllegalArgumentException("Resource class malformed.", ex);
143-
}
144-
}
145-
return (T) res;
14667
}
14768

14869
/** Returns the api endpoint for <strong>this</strong> client instance. */
@@ -193,14 +114,6 @@ void notifyAuthError(Response<?, ResponseBody> rawResponse) {
193114
}
194115
}
195116

196-
/** Throws an exception if class was declared non-static or non-final. */
197-
private static void checkResourceClassDeclaration(Class<? extends Resource> resource) {
198-
int modifiers = resource.getModifiers();
199-
if (resource.isLocalClass() || (resource.isMemberClass() && !Modifier.isStatic(modifiers))) {
200-
throw new IllegalArgumentException("Resource class must be declared static.");
201-
}
202-
}
203-
204117
/**
205118
* Build a new {@link XingApi}.
206119
* <p>
@@ -296,7 +209,6 @@ public static final class CustomStep extends BuildStep<CustomStep> {
296209
* @since 2.1.0
297210
*/
298211
public static class BuildStep<T extends BuildStep> {
299-
private final List<Factory> resourceFactory = new ArrayList<>();
300212
private OkHttpClient.Builder clientBuilder;
301213
private Moshi.Builder moshiBuilder;
302214
private Executor callbackExecutor;
@@ -306,12 +218,6 @@ public static class BuildStep<T extends BuildStep> {
306218
apiEndpoint = HttpUrl.parse("https://api.xing.com/");
307219
}
308220

309-
/** Add a resource factory for a specific {@linkplain Resource resource}. */
310-
public final T addResourceFactory(Resource.Factory factory) {
311-
resourceFactory.add(checkNotNull(factory, "factory == null"));
312-
return self();
313-
}
314-
315221
/**
316222
* Change the api endpoint.
317223
* <p>
@@ -393,7 +299,7 @@ public final XingApi build() {
393299
CallbackAdapter adapter = Platform.get().callbackAdapter(callbackExecutor);
394300
Converter converter = new Converter(moshiBuilder.build());
395301

396-
return new XingApi(clientBuilder().build(), apiEndpoint, converter, adapter, callbackExecutor, resourceFactory);
302+
return new XingApi(clientBuilder().build(), apiEndpoint, converter, adapter, callbackExecutor);
397303
}
398304
}
399305
}

api-client/src/main/java/com/xing/api/resources/BookmarksResource.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,8 @@
3030
* Provides methods which allow access to a {@linkplain com.xing.api.data.profile.XingUser user's} bookmarks.
3131
*/
3232
public class BookmarksResource extends Resource {
33-
public static final Resource.Factory FACTORY = new Resource.Factory(BookmarksResource.class) {
34-
@Override public Resource create(XingApi api) {
35-
return new BookmarksResource(api);
36-
}
37-
};
38-
3933
/** Creates a resource instance. This should be the only constructor declared by child classes. */
40-
BookmarksResource(XingApi api) {
34+
public BookmarksResource(XingApi api) {
4135
super(api);
4236
}
4337

api-client/src/main/java/com/xing/api/resources/ContactsResource.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,8 @@
3535
* respond to contact requests.
3636
*/
3737
public class ContactsResource extends Resource {
38-
public static final Resource.Factory FACTORY = new Resource.Factory(ContactsResource.class) {
39-
@Override public Resource create(XingApi api) {
40-
return new ContactsResource(api);
41-
}
42-
};
43-
4438
/** Creates a resource instance. This should be the only constructor declared by child classes. */
45-
ContactsResource(XingApi api) {
39+
public ContactsResource(XingApi api) {
4640
super(api);
4741
}
4842

api-client/src/main/java/com/xing/api/resources/GroupsResource.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,8 @@
3434
* Resource for all the possible groups calls.
3535
*/
3636
public class GroupsResource extends Resource {
37-
public static final Resource.Factory FACTORY = new Resource.Factory(GroupsResource.class) {
38-
@Override public Resource create(XingApi api) {
39-
return new GroupsResource(api);
40-
}
41-
};
42-
4337
/** Creates a resource instance. This should be the only constructor declared by child classes. */
44-
protected GroupsResource(XingApi api) {
38+
public GroupsResource(XingApi api) {
4539
super(api);
4640
}
4741

api-client/src/main/java/com/xing/api/resources/JobsResource.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,8 @@
3131
* criteria or recommended to a user by id.
3232
*/
3333
public class JobsResource extends Resource {
34-
public static final Resource.Factory FACTORY = new Resource.Factory(JobsResource.class) {
35-
@Override public Resource create(XingApi api) {
36-
return new JobsResource(api);
37-
}
38-
};
39-
4034
/** Creates a resource instance. This should be the only constructor declared by child classes. */
41-
JobsResource(XingApi api) {
35+
public JobsResource(XingApi api) {
4236
super(api);
4337
}
4438

0 commit comments

Comments
 (0)