Skip to content

Commit aa80765

Browse files
authored
Merge pull request dropbox#114 from dropbox/java_changes
Several updates.
2 parents 79d5aff + a38a70b commit aa80765

File tree

15 files changed

+312
-54
lines changed

15 files changed

+312
-54
lines changed

examples/global-callbacks/src/main/java/com/dropbox/core/examples/global-callbacks/DbxExampleGlobalCallbackFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
public class DbxExampleGlobalCallbackFactory implements DbxGlobalCallbackFactory {
1010
@Override
11-
public <T> DbxRouteErrorCallback<T> createRouteErrorCallback(T routeError) {
11+
public <T> DbxRouteErrorCallback<T> createRouteErrorCallback(String userId, T routeError) {
1212
if (routeError instanceof ListFolderError) {
1313
return new DbxExampleListFolderErrorCallback<T>();
1414
} else if (routeError instanceof LookupError) {
@@ -19,7 +19,7 @@ public <T> DbxRouteErrorCallback<T> createRouteErrorCallback(T routeError) {
1919
}
2020

2121
@Override
22-
public DbxExampleNetworkErrorCallback createNetworkErrorCallback() {
22+
public DbxExampleNetworkErrorCallback createNetworkErrorCallback(String userId) {
2323
return new DbxExampleNetworkErrorCallback();
2424
}
2525
}

generator/java.stoneg.py

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def get_underlying_type(data_type, allow_lists=True):
308308
return data_type
309309

310310

311-
def union_factory_create_method_name(data_type, value_fields_subset):
311+
def union_create_with_method_name(data_type, value_fields_subset):
312312
if len(value_fields_subset) > 0:
313313
method_suffix = 'And%s' % _capwords(value_fields_subset[0].name)
314314
else:
@@ -601,6 +601,8 @@ def __lt__(self, other):
601601
'If this argument is specified, an update Javadoc references file ' +
602602
'will be saved to the given location. It is OK if this file does not ' +
603603
'exist.')
604+
_CMDLINE_PARSER.add_argument('--unused-classes-to-generate', default=None, help='Specify types ' +
605+
'that we want to generate regardless of whether they are used.')
604606

605607
class JavaCodeGenerator(CodeGenerator):
606608
cmdline_parser = _CMDLINE_PARSER
@@ -2033,6 +2035,9 @@ def update_serializer_visibility(self, data_type_fq_name, visibility):
20332035
self._serializer_visibility[data_type], visibility
20342036
)
20352037

2038+
def mark_data_type_as_used(self, data_type):
2039+
self._client_data_types.add(data_type)
2040+
20362041

20372042
class JavaReferences(object):
20382043

@@ -2372,6 +2377,9 @@ def generate_all(self):
23722377

23732378
self.generate_client()
23742379

2380+
# some classes are unused, but we still want them to be generated
2381+
self._mark_special_unused_classes()
2382+
23752383
for namespace in self.api.namespaces.values():
23762384
self.generate_namespace(namespace)
23772385

@@ -2467,6 +2475,55 @@ def generate_namespace(self, namespace):
24672475
if namespace.routes:
24682476
self.generate_namespace_routes(namespace)
24692477

2478+
def _mark_special_unused_classes(self):
2479+
j = self.j
2480+
2481+
if not self.g.args.unused_classes_to_generate:
2482+
return
2483+
2484+
special_class_names = self.g.args.unused_classes_to_generate.split(', ')
2485+
2486+
if not special_class_names:
2487+
return
2488+
2489+
special_data_types = [
2490+
unwrap_nullable(data_type)[0]
2491+
for namespace in j.stone_api.namespaces.values()
2492+
for data_type in namespace.data_types
2493+
if data_type.name in special_class_names
2494+
]
2495+
2496+
all_special_data_types = set()
2497+
2498+
# mark all special types public and used, and likewise mark all of their
2499+
# referenced types as public and used
2500+
2501+
def _propagate_changes(data_type):
2502+
all_special_data_types.add(data_type)
2503+
2504+
if is_void_type(data_type) or not is_user_defined_type(data_type):
2505+
return
2506+
2507+
field_types = [unwrap_nullable(f.data_type)[0] for f in data_type.all_fields]
2508+
for field_type in field_types:
2509+
if field_type not in all_special_data_types:
2510+
_propagate_changes(field_type)
2511+
if data_type.parent_type:
2512+
if data_type.parent_type not in all_special_data_types:
2513+
_propagate_changes(data_type.parent_type)
2514+
2515+
for data_type in special_data_types:
2516+
_propagate_changes(data_type)
2517+
2518+
for data_type in all_special_data_types:
2519+
if is_user_defined_type(data_type) and not is_void_type(data_type):
2520+
data_type_fq_name = j.stone_fq_name(data_type)
2521+
2522+
# mark public
2523+
j.update_data_type_visibility(data_type_fq_name, Visibility.PUBLIC)
2524+
# mark as being referenced somewhere so that we generate
2525+
j.mark_data_type_as_used(data_type)
2526+
24702527
def generate_namespace_routes(self, namespace):
24712528
assert isinstance(namespace, ApiNamespace), repr(namespace)
24722529

@@ -2858,15 +2915,15 @@ def generate_route_upload_call(self, route, arg_var):
28582915
JavaClass('com.dropbox.core.http.HttpRequestor.Uploader')),
28592916
after=';',
28602917
)
2861-
w.out('return new %s(_uploader);', j.route_uploader_class(route))
2918+
w.out('return new %s(_uploader, this.client.getUserId());', j.route_uploader_class(route))
28622919

28632920
def generate_data_type(self, data_type):
28642921
"""Generate a class definition for a datatype (a struct or a union)."""
28652922
assert is_user_defined_type(data_type), repr(data_type)
28662923

28672924
j = self.j
28682925

2869-
if not (self.g.args.data_types_only or j.is_used_by_client(data_type)):
2926+
if not self.g.args.data_types_only and not j.is_used_by_client(data_type):
28702927
return
28712928

28722929
with self.class_writer(data_type) as w:
@@ -2976,8 +3033,8 @@ def generate_data_type_union(self, data_type):
29763033
for field in static_fields:
29773034
singleton_args = ', '.join(["Tag.%s" % j.field_tag_enum_name(field)])
29783035
w.javadoc(field)
2979-
method_name = union_factory_create_method_name(data_type, [])
2980-
w.out('public static final %s %s = %s.%s(%s);',
3036+
method_name = union_create_with_method_name(data_type, [])
3037+
w.out('public static final %s %s = new %s().%s(%s);',
29813038
j.java_class(data_type),
29823039
j.field_static_instance(field),
29833040
j.java_class(data_type),
@@ -2997,7 +3054,14 @@ def generate_data_type_union(self, data_type):
29973054
#
29983055
# Constructors
29993056
#
3000-
def _gen_factory_method(data_type, value_fields_subset):
3057+
3058+
w.out('')
3059+
w.javadoc('Private default constructor, so that object is uninitializable publicly.')
3060+
with w.block('private %s()', j.java_class(data_type)):
3061+
pass
3062+
w.out('')
3063+
3064+
def _gen_create_with_method(data_type, value_fields_subset):
30013065
w.out('')
30023066
w.javadoc(data_type,
30033067
fields=value_fields_subset,
@@ -3009,18 +3073,18 @@ def _gen_factory_method(data_type, value_fields_subset):
30093073
for f in value_fields_subset
30103074
],
30113075
))
3012-
method_name = union_factory_create_method_name(data_type, value_fields_subset)
3013-
with w.block('private static %s %s(%s)', j.java_class(data_type), method_name, formatted_args):
3014-
w.out('final %s result = new %s();', j.java_class(data_type), j.java_class(data_type))
3076+
method_name = union_create_with_method_name(data_type, value_fields_subset)
3077+
with w.block('private %s %s(%s)', j.java_class(data_type), method_name, formatted_args):
3078+
w.out('%s result = new %s();', j.java_class(data_type), j.java_class(data_type))
30153079
w.out('result._tag = _tag;')
30163080
for field in value_fields_subset:
30173081
# don't perform validation in the private constructor
30183082
w.out('result.%s = %s;', j.param_name(field), j.param_name(field))
30193083
w.out('return result;')
30203084

3021-
_gen_factory_method(data_type, [])
3085+
_gen_create_with_method(data_type, [])
30223086
for f in value_fields:
3023-
_gen_factory_method(data_type, [f])
3087+
_gen_create_with_method(data_type, [f])
30243088

30253089
#
30263090
# Field getters/constructors
@@ -3120,8 +3184,8 @@ def generate_data_type_union_field_methods(self, data_type):
31203184
j.java_class(field),
31213185
):
31223186
self.generate_field_validation(field, value_name="value", omit_arg_name=True, allow_default=False)
3123-
method_name = union_factory_create_method_name(data_type, [field])
3124-
w.out('return %s.%s(Tag.%s, %s);',
3187+
method_name = union_create_with_method_name(data_type, [field])
3188+
w.out('return new %s().%s(Tag.%s, %s);',
31253189
j.java_class(data_type),
31263190
method_name,
31273191
j.field_tag_enum_name(field),
@@ -3502,8 +3566,8 @@ def generate_route_uploader(self, route):
35023566
params=(('httpUploader', 'Initiated HTTP upload request'),),
35033567
throws=(('NullPointerException', 'if {@code httpUploader} is {@code null}'),)
35043568
)
3505-
with w.block('public %s(HttpRequestor.Uploader httpUploader)', j.route_uploader_class(route)):
3506-
w.out('super(httpUploader, %s, %s);',
3569+
with w.block('public %s(HttpRequestor.Uploader httpUploader, String userId)', j.route_uploader_class(route)):
3570+
w.out('super(httpUploader, %s, %s, userId);',
35073571
w.java_serializer(route.result_data_type),
35083572
w.java_serializer(route.error_data_type))
35093573

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.dropbox.core;
2+
3+
import com.dropbox.core.v2.auth.AccessError;
4+
5+
/**
6+
* Gets thrown when invalid access occurs.
7+
*/
8+
public class AccessErrorException extends DbxException {
9+
private static final long serialVersionUID = 0;
10+
11+
private final AccessError accessError;
12+
13+
public AccessError getAccessError() {
14+
return accessError;
15+
}
16+
17+
public AccessErrorException(String requestId, String message, AccessError accessError) {
18+
super(requestId, message);
19+
this.accessError = accessError;
20+
}
21+
}

src/main/java/com/dropbox/core/DbxRequestUtil.java

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@
1212
import java.util.Map;
1313
import java.util.Random;
1414

15+
import com.fasterxml.jackson.core.JsonProcessingException;
16+
1517
import com.dropbox.core.http.HttpRequestor;
1618
import com.dropbox.core.json.JsonReadException;
1719
import com.dropbox.core.json.JsonReader;
1820
import com.dropbox.core.util.IOUtil;
1921
import com.dropbox.core.util.StringUtil;
22+
import com.dropbox.core.v2.auth.AccessError;
23+
import com.dropbox.core.v2.common.PathRootError;
24+
import com.dropbox.core.v2.common.PathRootError.Serializer;
2025
import com.dropbox.core.v2.callbacks.DbxGlobalCallbackFactory;
2126
import com.dropbox.core.v2.callbacks.DbxNetworkErrorCallback;
2227

@@ -276,21 +281,56 @@ public static String parseErrorBody(String requestId, int statusCode, byte[] bod
276281
}
277282
}
278283

279-
public static DbxException unexpectedStatus(HttpRequestor.Response response)
284+
public static DbxException unexpectedStatus(HttpRequestor.Response response) throws NetworkIOException, BadResponseException {
285+
return DbxRequestUtil.unexpectedStatus(response, null);
286+
}
287+
288+
public static DbxException unexpectedStatus(HttpRequestor.Response response, String userId)
280289
throws NetworkIOException, BadResponseException {
281-
DbxException networkError;
282290

283291
String requestId = getRequestId(response);
284-
byte[] body = loadErrorBody(response);
285-
String message = parseErrorBody(requestId, response.getStatusCode(), body);
292+
String message = null;
293+
DbxException networkError;
286294

287295
switch (response.getStatusCode()) {
288296
case 400:
297+
message = DbxRequestUtil.messageFromResponse(response, requestId);
289298
networkError = new BadRequestException(requestId, message);
290299
break;
291300
case 401:
301+
message = DbxRequestUtil.messageFromResponse(response, requestId);
292302
networkError = new InvalidAccessTokenException(requestId, message);
293303
break;
304+
case 403:
305+
try {
306+
ApiErrorResponse<AccessError> accessErrorResponse = new ApiErrorResponse.Serializer<AccessError>(AccessError.Serializer.INSTANCE)
307+
.deserialize(response.getBody());
308+
if (accessErrorResponse.getUserMessage() != null) {
309+
message = accessErrorResponse.getUserMessage().toString();
310+
}
311+
AccessError accessError = accessErrorResponse.getError();
312+
networkError = new AccessErrorException(requestId, message, accessError);
313+
} catch (JsonProcessingException ex) {
314+
throw new BadResponseException(requestId, "Bad JSON: " + ex.getMessage(), ex);
315+
} catch (IOException ex) {
316+
throw new NetworkIOException(ex);
317+
}
318+
break;
319+
case 422:
320+
try {
321+
ApiErrorResponse<PathRootError> pathRootErrorResponse = new ApiErrorResponse.Serializer<PathRootError>(Serializer.INSTANCE)
322+
.deserialize(response.getBody());
323+
if (pathRootErrorResponse.getUserMessage() != null) {
324+
message = pathRootErrorResponse.getUserMessage().toString();
325+
}
326+
PathRootError pathRootError = pathRootErrorResponse.getError();
327+
networkError = new PathRootErrorException(requestId, message, pathRootError);
328+
} catch (JsonProcessingException ex) {
329+
throw new BadResponseException(requestId, "Bad JSON: " + ex.getMessage(), ex);
330+
} catch (IOException ex) {
331+
throw new NetworkIOException(ex);
332+
}
333+
break;
294334
case 429:
295335
try {
296336
int backoffSecs = Integer.parseInt(getFirstHeader(response, "Retry-After"));
@@ -329,13 +369,19 @@ public static DbxException unexpectedStatus(HttpRequestor.Response response)
329369

330370
DbxGlobalCallbackFactory factory = DbxRequestUtil.sharedCallbackFactory;
331371
if (factory != null) {
332-
DbxNetworkErrorCallback callback = factory.createNetworkErrorCallback();
372+
DbxNetworkErrorCallback callback = factory.createNetworkErrorCallback(userId);
333373
callback.onNetworkError(networkError);
334374
}
335375

336376
return networkError;
337377
}
338378

379+
private static String messageFromResponse(HttpRequestor.Response response, String requestId) throws NetworkIOException, BadResponseException {
380+
byte[] body = loadErrorBody(response);
381+
String message = parseErrorBody(requestId, response.getStatusCode(), body);
382+
return message;
383+
}
384+
339385
public static <T> T readJsonFromResponse(JsonReader<T> reader, HttpRequestor.Response response)
340386
throws BadResponseException, NetworkIOException {
341387
try {

src/main/java/com/dropbox/core/DbxUploader.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,16 @@ public abstract class DbxUploader<R, E, X extends DbxApiException> implements Cl
5050
private boolean closed;
5151
private boolean finished;
5252

53-
protected DbxUploader(HttpRequestor.Uploader httpUploader, StoneSerializer<R> responseSerializer, StoneSerializer<E> errorSerializer) {
53+
private final String userId;
54+
55+
protected DbxUploader(HttpRequestor.Uploader httpUploader, StoneSerializer<R> responseSerializer, StoneSerializer<E> errorSerializer, String userId) {
5456
this.httpUploader = httpUploader;
5557
this.responseSerializer = responseSerializer;
5658
this.errorSerializer = errorSerializer;
5759

5860
this.closed = false;
5961
this.finished = false;
62+
this.userId = userId;
6063
}
6164

6265
protected abstract X newException(DbxWrappedException error);
@@ -218,7 +221,7 @@ public R finish() throws X, DbxException {
218221
return responseSerializer.deserialize(response.getBody());
219222
}
220223
else if (response.getStatusCode() == 409) {
221-
DbxWrappedException wrapped = DbxWrappedException.fromResponse(errorSerializer, response);
224+
DbxWrappedException wrapped = DbxWrappedException.fromResponse(errorSerializer, response, this.userId);
222225
throw newException(wrapped);
223226
}
224227
else {

src/main/java/com/dropbox/core/DbxWrappedException.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public LocalizedText getUserMessage() {
3939
return userMessage;
4040
}
4141

42-
public static <T> DbxWrappedException fromResponse(StoneSerializer<T> errSerializer, HttpRequestor.Response response)
42+
public static <T> DbxWrappedException fromResponse(StoneSerializer<T> errSerializer, HttpRequestor.Response response, String userId)
4343
throws IOException, JsonParseException {
4444
String requestId = DbxRequestUtil.getRequestId(response);
4545

@@ -49,13 +49,13 @@ public static <T> DbxWrappedException fromResponse(StoneSerializer<T> errSeriali
4949
T routeError = apiResponse.getError();
5050

5151
DbxGlobalCallbackFactory factory = DbxRequestUtil.sharedCallbackFactory;
52-
DbxWrappedException.executeBlockForObject(factory, routeError);
53-
DbxWrappedException.executeOtherBlocks(factory, routeError);
52+
DbxWrappedException.executeBlockForObject(factory, userId, routeError);
53+
DbxWrappedException.executeOtherBlocks(factory, userId, routeError);
5454

5555
return new DbxWrappedException(routeError, requestId, apiResponse.getUserMessage());
5656
}
5757

58-
public static void executeOtherBlocks(DbxGlobalCallbackFactory factory, Object routeError) {
58+
public static void executeOtherBlocks(DbxGlobalCallbackFactory factory, String userId, Object routeError) {
5959
try {
6060
// Recursively looks at union errors and the union's current tag type. If there is a handler
6161
// for the current tag type, it is executed.
@@ -66,7 +66,7 @@ public static void executeOtherBlocks(DbxGlobalCallbackFactory factory, Object r
6666
if (f.getName().equalsIgnoreCase(fName) ) {
6767
f.setAccessible(true);
6868
Object fieldValue = f.get(routeError);
69-
DbxWrappedException.executeBlockForObject(factory, fieldValue);
69+
DbxWrappedException.executeBlockForObject(factory, userId, fieldValue);
7070
break;
7171
}
7272
}
@@ -75,9 +75,9 @@ public static void executeOtherBlocks(DbxGlobalCallbackFactory factory, Object r
7575
}
7676
}
7777

78-
public static <T> void executeBlockForObject(DbxGlobalCallbackFactory factory, T routeError) {
78+
public static <T> void executeBlockForObject(DbxGlobalCallbackFactory factory, String userId, T routeError) {
7979
if (factory != null) {
80-
DbxRouteErrorCallback<T> callback = factory.createRouteErrorCallback(routeError);
80+
DbxRouteErrorCallback<T> callback = factory.createRouteErrorCallback(userId, routeError);
8181
if (callback != null) {
8282
callback.setRouteError(routeError);
8383
callback.run();

0 commit comments

Comments
 (0)