Cloud Endpoints 生成的代码中 @JSONString 注解的非法参数异常

2 投票
1 回答
1449 浏览
提问于 2025-04-17 18:44

我正在开发一个Google Cloud Endpoint的网络服务,经过一番努力终于让身份验证(auth)正常工作了,但现在遇到了一些生成代码的问题。

我构建了我的ProtoRPC消息,使用了整数类型的字段来表示对象ID、客户端ID和高水位标记。

class NoteMessage(messages.Message):
    id = messages.IntegerField(1)
    client_id = messages.IntegerField(2)
    high_water_mark = messages.IntegerField(5)
    ...

这段代码生成了Java源代码,其中在long类型的字段上加了@JsonString这个属性。但是当我从服务器收到响应时,出现了以下错误。

E/AndroidRuntime( 9231): java.lang.IllegalArgumentException: number type formatted as a JSON number cannot use @JsonString annotation [key id, field private java.lang.Long com.google.api.services.notes.model.NoteApiMessagesNoteMessage.id]
E/AndroidRuntime( 9231):    at com.google.common.base.Preconditions.checkArgument(Preconditions.java:119)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:599)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parse(JsonParser.java:350)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:586)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parseArray(JsonParser.java:456)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:549)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parse(JsonParser.java:350)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:586)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonParser.parse(JsonParser.java:289)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:76)
E/AndroidRuntime( 9231):    at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:71)
E/AndroidRuntime( 9231):    at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:495)
E/AndroidRuntime( 9231):    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:465)
E/AndroidRuntime( 9231):    at com.ryanharter.hashnote.sync.SyncAdapter.syncNotes(SyncAdapter.java:187)
E/AndroidRuntime( 9231):    at com.ryanharter.hashnote.sync.SyncAdapter.onPerformSync(SyncAdapter.java:110)
E/AndroidRuntime( 9231):    at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:254)

我似乎找不到任何可以控制序列化或反序列化的地方,那这在Java中应该怎么运作呢?

1 个回答

3

正如在另一篇帖子中提到的,这个问题是由于protorpc库的一个小问题引起的。谷歌的API客户端库希望在JSON中,int64uint64字段是字符串,因为JavaScript本身只能处理(由于精度问题)最大到2**53的整数。

在谷歌的“Discovery”API标准的类型格式文档中,你可以看到这些类型的预期格式。然而,protorpc库并没有使用相同的语义,我们仍在确定正确的处理方式。

所以,当你使用

id = messages.IntegerField(1)

时,你使用的是IntegerField的默认变体,即messages.Variant.INT64。这使得Java客户端库期待一个像这样的JSON字符串

{'id': '123456789'}

而实际上从protorpc返回的响应是

{'id': 123456789}

作为你应用程序的临时解决办法,可以使用

id = messages.IntegerField(1, variant=messages.Variant.INT32)

或者如果你的ID需要超过32位的大小,可以使用:

id = messages.StringField(1)

附言:

顺便提一下,我建议你看看Endpoints Proto Datastore API。我们做了一些关于它使用的视频教程

要解决endpoints-proto-datastore的同样问题,你需要导入

from protorpc import messages
from endpoints_proto_datastore.ndb import EndpointsVariantIntegerProperty

并为你的属性使用

attr1 = EndpointsVariantIntegerProperty(variant=messages.Variant.INT32)

撰写回答