TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Stop Writing REST API Clients

153 pointsby ttezelabout 12 years ago

42 comments

tommorrisabout 12 years ago
Substitute "XML" for "JSON" and we've now come full circle.<p>The point about REST is that it is self-describing. And ideally should be using the same URIs as the version people clicking around in Firefox or Chrome see. The API is just the XML or JSON or whatever is flavour of the week version of the HTML version.<p>(Or we could use embedded data—microformats, microdata, RDFa—and get rid of that distinction.)
评论 #5274836 未加载
评论 #5274853 未加载
评论 #5274832 未加载
评论 #5274889 未加载
评论 #5275034 未加载
michaelwabout 12 years ago
Sigh. This is optimizing for the wrong problem.<p>Stop creating REST APIs that are only level 1 or 2 (see <a href="http://martinfowler.com/articles/richardsonMaturityModel.html" rel="nofollow">http://martinfowler.com/articles/richardsonMaturityModel.htm...</a> ).<p>Start writing HATEOS systems where the client is coupled to the semantic rather than the syntax.<p>Machine parseable interface descriptions might get rid of some boilerplate but it doesn't make for a more robust client-server relationship.
评论 #5274982 未加载
评论 #5274858 未加载
评论 #5274838 未加载
评论 #5275575 未加载
评论 #5274747 未加载
petercooperabout 12 years ago
We could give a name to the language we use to define such files. It's a language that defines Web services, so perhaps Web Services Description Language? :-) <a href="http://en.wikipedia.org/wiki/Web_Services_Description_Language" rel="nofollow">http://en.wikipedia.org/wiki/Web_Services_Description_Langua...</a><p>Flippancy aside, maybe there's a need for a next generation of this that skips all the XML headaches after all.
评论 #5275615 未加载
评论 #5274860 未加载
评论 #5274748 未加载
ubermammalabout 12 years ago
I don't see how writing JSON REST API descriptions isn't practically the same as writing REST API clients anyway: they're still clients, just written declaratively rather than procedurally.<p>If the point is "stop writing procedural REST API clients and write them declaratively instead" then that advice is by no means restricted to REST API clients.<p>If the point is "hey, I noticed that REST API clients are another thing that we can now comfortably write declaratively" then OK.
TelmoMenezesabout 12 years ago
Am I the only one who doesn't like receiving direct orders from article titles?
评论 #5274812 未加载
评论 #5274780 未加载
评论 #5275162 未加载
评论 #5275387 未加载
评论 #5274763 未加载
评论 #5274776 未加载
评论 #5310264 未加载
评论 #5275070 未加载
评论 #5274827 未加载
评论 #5274824 未加载
mixedbitabout 12 years ago
This article is not at all about REST, it is about RPC and its shortcomings. These shortcoming were fixed by REST, and the author of the article rediscovers these fixes.<p>A key features of a REST API is that is self describable, in a sense, that it has a single entry point from which a generic client can automatically discover available resources and actions. APIs in the given examples are not like this, they require custom clients that are strongly coupled with an application. These are not REST APIs but RPC APIs.
评论 #5275680 未加载
评论 #5275348 未加载
autarchabout 12 years ago
All that these sorts of description produce is a low-level API. That can be useful, but what's really needed are high-level APIs that provide meaningful semnatics:<p><pre><code> my $me = Facebook-&#62;new( username =&#62; 'autarch' ); $me-&#62;post_status("I'm on Hacker News writing this comment"); my $friend = Facebook-&#62;new( username =&#62; 'imaginary' ); $me-&#62;post_on_wall( $friend, "Hey buddy, I am on Hacker News writing this comment" );</code></pre>
评论 #5275086 未加载
ayushgtaabout 12 years ago
swagger (<a href="http://developers.helloreverb.com/swagger/" rel="nofollow">http://developers.helloreverb.com/swagger/</a>) has been doing whats proposed here. By describing your APIs with swagger-spec you get a beautifully documented APIs, code generation of client libraries and some more stuff: <a href="https://github.com/wordnik/swagger-core/wiki/Downloads" rel="nofollow">https://github.com/wordnik/swagger-core/wiki/Downloads</a>
hoovabout 12 years ago
While this has some benefits, it seems like a slippery slope leading back to SOAP.
评论 #5274618 未加载
评论 #5274861 未加载
taudeabout 12 years ago
Hmmm....JSON documents (jsonSpec) describing the restful services is the new WSDL, feels like 2002 all over again.<p>I think too many people consume REST APIs in different manners, utilizing different data in unique relations. This is the beauty of it.
评论 #5274782 未加载
评论 #5274826 未加载
ms123about 12 years ago
Hypermedia APIs are an approach to solve this problem. It essentially does what you did, and add some other benefits like de-coupling URIs.
评论 #5275395 未加载
pfrazeabout 12 years ago
We've been experimenting with this at my office. We use yaml descriptions of all of our routes to generate test coverage. We plan to later generate our documentation and client libraries with the same docs.<p>Document-generated server behavior is something we're researching as well, to possibly represent business logic. We're hoping that patterns can be found and condensed into notations, like Regular Expressions do for string-parsing. We'll post about anything that we come up with.<p>One of my side projects us an Ajax library which allows javascript to respond to requests (LinkJS [1]). It has a helper object called the Navigator, which is like a miniature Web Agent. It retains a context, and uses the Link header from the response to populate the navigator with relations. It works out like this:<p><pre><code> var nav = Link.navigator('http://mysite.com'); nav.collection('users').item('pfraze').getJson() .then(function(res) { console.log(res.body); // =&#62; { name:'pfraze', role:'admin' ...} }) .except(function(err) { console.log(err.message); // =&#62; 404: not found console.log(err.response.status); // =&#62; 404 }); </code></pre> The advantage is that the link header is a relatively condensed representation of the resource graph. As a result, it's not a problem to send it and process it every time. You do gain latency, but the internet is only getting faster, and caching can be used. Meanwhile, the server can rewire links without interrupting their clients.<p>1 <a href="https://github.com/pfraze/linkjs" rel="nofollow">https://github.com/pfraze/linkjs</a>
id_heavenabout 12 years ago
&#62; This doesn't scale.<p>Most overused phrase right there.
feralmoanabout 12 years ago
Isn't this what <a href="http://json-schema.org" rel="nofollow">http://json-schema.org</a> aims to provide? Or am I missing something. It's a solid spec.
评论 #5274773 未加载
评论 #5275370 未加载
mpweiherabout 12 years ago
While I agree with the title, I am not so sure about the solution presented. HATEOAS, whether encoded in JSON or XML, can only give you so much information about the semantics of links.<p>IMHO, what's needed is better support for "generic" REST in programming languages and/or libraries. Objective-Smalltalk (<a href="http://objective.st" rel="nofollow">http://objective.st</a>) features "Polymorphic Identifiers", which make it possible to both interact directly and abstract over web interfaces.<p>To reference a URL, just write it down:<p><pre><code> news := http://news.ycombinator.com </code></pre> Arguments can be added without string processing:<p><pre><code> #!/usr/local/bin/stsh #-zip:zipCode ref:http://zip.elevenbasetwo.com getWithArgs zip:zipCode </code></pre> This is a file downloader, similar to curl:<p><pre><code> #!/usr/local/bin/stsh #-&#60;void&#62;scurl:&#60;ref&#62;urlref fileComponent := urlref url path lastPathComponent. file:{fileComponent} := urlref value. </code></pre> For abstraction, you can build your own schemes, either directly in code or by composing/modifying other schemes. For example, if I want to look up RFCs, I can define the rfc scheme:<p><pre><code> scheme:rfc := ref:http://datatracker.ietf.org/doc asScheme </code></pre> Or I can compose schemes so the rfc scheme looks in a bunch of different places (memory, local directoy, several http/ftp servers).
jconnollyabout 12 years ago
Stop writing self-documenting API specs and settle on a hypermedia spec, like Hal or Siren! reply
评论 #5274656 未加载
dgritskoabout 12 years ago
This is essentially trying to solve the same problem as Swagger. Swagger is "a specification and complete framework implementation for describing, producing, consuming, and visualizing RESTful web services" [1]. Check out the spec on GitHub here [2].<p>[1]: <a href="http://developers.helloreverb.com/swagger/" rel="nofollow">http://developers.helloreverb.com/swagger/</a><p>[2]: <a href="https://github.com/wordnik/swagger-core/wiki" rel="nofollow">https://github.com/wordnik/swagger-core/wiki</a>
unclebucknastyabout 12 years ago
There is a lot of talk about this idea being SOAP-like, but I disagree.<p>SOAP was insane and its counterpart, WSDL (which is really the part that is most comparable to this idea), was even more insane.<p>But, the basic premise was not bad. It was the execution which sucked by trying to account for every situation, adding namespaces, etc. And if you ever worked with language libs designed to interface with SOAP/WSDL, it would make you slap a bunny.<p>With this idea, however, adding an optional JSON-based descriptor language could be helpful. Key would be to keep it simple, allowing the bare mnimum number of data types, with one simple array structure for collections. Allow object definitions with an infinite number of nesting levels, and that would be it. I wouldn't even get into optional vs required stuff, validation, etc. That stuff should stay at the application level. Why stuff it into the interface layer?<p>From there, it would be easy to develop libraries to generate clients in any language for any API just by feeding it the JSON descriptor. Or (as I think the author intended) just use one universal client that any app can use. For languages that aren't strongly typed anyway, the latter would be fine.<p>Someone mentioned that it would require the server side devs to keep the descriptor in sync with the code. No biggie for apps that already offer client libs in different languages and must keep them up to date anyway. Not to mention there should be some doc that needs to be kept in sync (REST is not typically self documenting in reality).<p>In any event it wouldn't be required. What would be the harm in creating a standard for those apps that choose to use it?
VoxPelliabout 12 years ago
Can't we just stop writing clients for specific REST API:s period and rather just build one good API client that can easily be extended and adapted to any API?<p>That's the path I've been using in all projects lately - because frankly - I don't want to deal with a bunch of different API clients for Twitter, Facebook, Soundcloud, Instagram or whatever sites it is that I integrate with - all those different syntaxes and all that duplicated code etc doesn't help me - I want all of their individual differences hidden away for me and colleagues behind a single well known syntax which I myself can extend to expose the resources and methods that I need - like if I need it a method for posting a photo for the API:s that support that and so on.<p>My advice today would be: Pick a good HTTP client, preferably with good OAuth support, and then build your own extendable API-client on top of that and integrate all the different API-resources you need with that client whenever you need them.
utopkaraabout 12 years ago
A client template library for REST API need to be Turing complete, otherwise it will be too weak to be able to handle complex services or complex client-side tasks, such as caching, dependency relations, data that span multiple services etc. Even if you make the template library simple, you'll need to wrap that with a layer of complex code. All you've done will be adding another layer on your code. You could re-design your code to fit a manageable design, but server side of the REST APIs are usually design by others whose priority is the code on the server side. So, by definition of the very task, the REST API client code have to be a complex soup where the client considerations mix up with those of the servers'.
ahallockabout 12 years ago
While I understand the allure of writing specs and using a unified library, good API clients are more terse, as they're written to take advantage of the programming language you're using, and understand the particulars and idioms of the API they're written against. For example, the client might pick up the correct environment variables for your API credentials, or reduce certain repetitive code.<p>Another example: I wrote a client that returns a queue message. Attached to that message are some helper methods for deleting, releasing, and touching the message. It makes your code cleaner and easier to understand.
dtjohnnymonkeyabout 12 years ago
I think Google is already doing this using a form of JSON-Schema: <a href="https://developers.google.com/discovery/" rel="nofollow">https://developers.google.com/discovery/</a>
spankaleeabout 12 years ago
Given that the prevailing sentiment is that REST is self-describing and the API description doc is unnecessary, are there any examples of client generators that work directly off of a REST service?<p>I'm curious how this works in practice. What about authorization and parts of the API that are only available to certain users, does the client generator need to be authenticated? Are there standards for describing the meta-data associated with URLs (validation, optional parameters, etc.)?
edandersenabout 12 years ago
The article fails to mention the existing JSON Schema and JSON Hyper-Schema standards that he is advocating: <a href="http://json-schema.org/" rel="nofollow">http://json-schema.org/</a><p>Both are currently used by Google's public APIs to auto-generate clients. Ruby/Python clients load the schema docs at runtime and do method_missing magic, Java/.NET clients generate static typed libraries periodically.
hhaririabout 12 years ago
How about stop calling REST something that is not. You'll be surprised how many things it will solve.
moondownerabout 12 years ago
There is for example RestTemplate from Spring for Java/Android apps, which solves this problem.<p><a href="http://static.springsource.org/spring-android/docs/1.0.x/reference/html/rest-template.html" rel="nofollow">http://static.springsource.org/spring-android/docs/1.0.x/ref...</a>
olegpabout 12 years ago
I've gone a step further and converted the JSON definition into JavaScript method calls: <a href="https://github.com/olegp/restwrapper" rel="nofollow">https://github.com/olegp/restwrapper</a><p>RPC FTW ;)
phatbyteabout 12 years ago
Can someone please explain me why it doesn't scale ? True question.
评论 #5274864 未加载
michaelmiorabout 12 years ago
So we solve the problem of too many REST clients via another REST client? I agree with ttezel, and unio does look pretty cool, but I got a chuckle out of this :)
dfamabout 12 years ago
I wrote a quick port to PHP that is installable via Composer. <a href="https://github.com/andruu/unio-php" rel="nofollow">https://github.com/andruu/unio-php</a>
erwanlabout 12 years ago
Yay, SOAP in JSON!
eintrabout 12 years ago
Yeah, let's do CORBA once again. No thanks.
评论 #5274783 未加载
评论 #5274811 未加载
评论 #5274869 未加载
johtsoabout 12 years ago
<a href="https://github.com/dstufft/slumber" rel="nofollow">https://github.com/dstufft/slumber</a>
spo81rtyabout 12 years ago
We need WSDL for REST to solve this problem. Then we could code generate clients.
whoisstanabout 12 years ago
I like the idea. This is useful to generate stubs.
arankineabout 12 years ago
so, define web services as a json file. JSON-SOAP?
pionarabout 12 years ago
Ha. So, now we're back to SOAP and WSDL's.
Uchikomaabout 12 years ago
There it is: Zombie SOAP again!
tbatteriiabout 12 years ago
skeptical programmer is skeptical this could ever work.
joelittlejohnabout 12 years ago
<a href="http://xkcd.com/927/" rel="nofollow">http://xkcd.com/927/</a>
manishsharanabout 12 years ago
I want to give you an idea of how bad things are with REST Api Client . This is a Maven POM for Google APIs for java web project that uses Google APIs for Profile, Drive and Oauth2. Its insane:<p><pre><code> &#60;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&#62; &#60;modelVersion&#62;4.0.0&#60;/modelVersion&#62; &#60;parent&#62; &#60;groupId&#62;com.google&#60;/groupId&#62; &#60;artifactId&#62;google&#60;/artifactId&#62; &#60;version&#62;5&#60;/version&#62; &#60;/parent&#62; &#60;groupId&#62;com.google.api.client&#60;/groupId&#62; &#60;artifactId&#62;google-plus-java-webapp-starter&#60;/artifactId&#62; &#60;packaging&#62;war&#60;/packaging&#62; &#60;version&#62;1.0.0&#60;/version&#62; &#60;name&#62;google-plus-java-webapp-starter&#60;/name&#62; &#60;description&#62; Web application example for the Google+ platform using JSON and OAuth 2 &#60;/description&#62; &#60;url&#62;https://code.google.com/p/google-plus-java-starter&#60;/url&#62; &#60;issueManagement&#62; &#60;system&#62;code.google.com&#60;/system&#62; &#60;url&#62;https://code.google.com/p/google-plus-java-starter/issues&#60;/url&#62; &#60;/issueManagement&#62; &#60;inceptionYear&#62;2011&#60;/inceptionYear&#62; &#60;prerequisites&#62; &#60;maven&#62;2.0.9&#60;/maven&#62; &#60;/prerequisites&#62; &#60;scm&#62; &#60;connection&#62; scm:hg:https://hg.codespot.com/p/google-plus-java-starter/ &#60;/connection&#62; &#60;developerConnection&#62; scm:hg:https://hg.codespot.com/p/google-plus-java-starter/ &#60;/developerConnection&#62; &#60;url&#62; https://code.google.com/p/google-plus-java-starter/source/browse/ &#60;/url&#62; &#60;/scm&#62; &#60;developers&#62; &#60;developer&#62; &#60;id&#62;jennymurphy&#60;/id&#62; &#60;name&#62;Jennifer Murphy&#60;/name&#62; &#60;organization&#62;Google&#60;/organization&#62; &#60;organizationUrl&#62;http://www.google.com&#60;/organizationUrl&#62; &#60;roles&#62; &#60;role&#62;owner&#60;/role&#62; &#60;role&#62;developer&#60;/role&#62; &#60;/roles&#62; &#60;timezone&#62;-8&#60;/timezone&#62; &#60;/developer&#62; &#60;/developers&#62; &#60;repositories&#62; &#60;!-- The repository for service specific Google client libraries. See http://code.google.com/p/google-api-java-client/wiki/APIs#Maven_support for more information --&#62; &#60;repository&#62; &#60;id&#62;google-api-services&#60;/id&#62; &#60;url&#62;http://mavenrepo.google-api-java-client.googlecode.com/hg&#60;/url&#62; &#60;/repository&#62; &#60;repository&#62; &#60;id&#62;google-api-services-drive&#60;/id&#62; &#60;url&#62;http://google-api-client-libraries.appspot.com/mavenrepo&#60;/url&#62; &#60;/repository&#62; &#60;/repositories&#62; &#60;build&#62; &#60;plugins&#62; &#60;plugin&#62; &#60;artifactId&#62;maven-compiler-plugin&#60;/artifactId&#62; &#60;version&#62;2.3.2&#60;/version&#62; &#60;configuration&#62; &#60;source&#62;1.6&#60;/source&#62; &#60;target&#62;1.6&#60;/target&#62; &#60;/configuration&#62; &#60;/plugin&#62; &#60;plugin&#62; &#60;groupId&#62;org.mortbay.jetty&#60;/groupId&#62; &#60;artifactId&#62;maven-jetty-plugin&#60;/artifactId&#62; &#60;configuration&#62; &#60;contextPath&#62;/&#60;/contextPath&#62; &#60;systemProperties&#62; &#60;systemProperty&#62; &#60;name&#62;configurationPath&#60;/name&#62; &#60;value&#62;./src/main/resources/config.properties&#60;/value&#62; &#60;/systemProperty&#62; &#60;/systemProperties&#62; &#60;/configuration&#62; &#60;/plugin&#62; &#60;/plugins&#62; &#60;finalName&#62;${project.artifactId}-${project.version}&#60;/finalName&#62; &#60;/build&#62; &#60;properties&#62; &#60;project.build.sourceEncoding&#62;UTF-8&#60;/project.build.sourceEncoding&#62; &#60;netbeans.hint.deploy.server&#62;gfv3ee6&#60;/netbeans.hint.deploy.server&#62; &#60;project.http.version&#62;1.13.1-beta&#60;/project.http.version&#62; &#60;project.oauth.version&#62;1.13.1-beta&#60;/project.oauth.version&#62; &#60;webapi.version&#62;6.0&#60;/webapi.version&#62; &#60;/properties&#62; &#60;dependencies&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.guava&#60;/groupId&#62; &#60;artifactId&#62;guava&#60;/artifactId&#62; &#60;version&#62;13.0.1&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.apis&#60;/groupId&#62; &#60;artifactId&#62;google-api-services-drive&#60;/artifactId&#62; &#60;version&#62;v2-rev53-1.13.2-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;!-- A generated library for Google+ APIs. Visit here for more info: http://code.google.com/p/google-api-java-client/wiki/APIs#Google+_API --&#62; &#60;groupId&#62;com.google.apis&#60;/groupId&#62; &#60;artifactId&#62;google-api-services-plus&#60;/artifactId&#62; &#60;version&#62;v1-rev22-1.8.0-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.api-client&#60;/groupId&#62; &#60;artifactId&#62;google-api-client&#60;/artifactId&#62; &#60;version&#62;1.13.2-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.api-client&#60;/groupId&#62; &#60;artifactId&#62;google-api-client-servlet&#60;/artifactId&#62; &#60;version&#62;1.13.1-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;!-- The Google OAuth Java client. Visit here for more info: http://code.google.com/p/google-oauth-java-client/ --&#62; &#60;groupId&#62;com.google.oauth-client&#60;/groupId&#62; &#60;artifactId&#62;google-oauth-client&#60;/artifactId&#62; &#60;version&#62;1.13.1-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.oauth-client&#60;/groupId&#62; &#60;artifactId&#62;google-oauth-client-servlet&#60;/artifactId&#62; &#60;version&#62;1.13.1-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.http-client&#60;/groupId&#62; &#60;artifactId&#62;google-http-client-gson&#60;/artifactId&#62; &#60;version&#62;1.13.1-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.code.gson&#60;/groupId&#62; &#60;artifactId&#62;gson&#60;/artifactId&#62; &#60;version&#62;2.1&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.http-client&#60;/groupId&#62; &#60;artifactId&#62;google-http-client&#60;/artifactId&#62; &#60;version&#62;1.13.1-beta&#60;/version&#62; &#60;/dependency&#62; &#60;!-- Third party dependencies --&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.http-client&#60;/groupId&#62; &#60;artifactId&#62;google-http-client-jackson2&#60;/artifactId&#62; &#60;version&#62;1.13.1-beta&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;javax&#60;/groupId&#62; &#60;artifactId&#62;javaee-web-api&#60;/artifactId&#62; &#60;version&#62;${webapi.version}&#60;/version&#62; &#60;scope&#62;provided&#60;/scope&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;org.apache.commons&#60;/groupId&#62; &#60;artifactId&#62;commons-lang3&#60;/artifactId&#62; &#60;version&#62;3.0.1&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;commons-logging&#60;/groupId&#62; &#60;artifactId&#62;commons-logging&#60;/artifactId&#62; &#60;version&#62;1.1.1&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;org.apache.httpcomponents&#60;/groupId&#62; &#60;artifactId&#62;httpclient&#60;/artifactId&#62; &#60;version&#62;4.0.3&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;org.apache.httpcomponents&#60;/groupId&#62; &#60;artifactId&#62;httpcore&#60;/artifactId&#62; &#60;version&#62;4.0.1&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;org.codehaus.jackson&#60;/groupId&#62; &#60;artifactId&#62;jackson-core-asl&#60;/artifactId&#62; &#60;version&#62;1.9.4&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;javax.jdo&#60;/groupId&#62; &#60;artifactId&#62;jdo2-api&#60;/artifactId&#62; &#60;version&#62;2.3-eb&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.code.findbugs&#60;/groupId&#62; &#60;artifactId&#62;jsr305&#60;/artifactId&#62; &#60;version&#62;1.3.9&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;com.google.protobuf&#60;/groupId&#62; &#60;artifactId&#62;protobuf-java&#60;/artifactId&#62; &#60;version&#62;2.2.0&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;javax.transaction&#60;/groupId&#62; &#60;artifactId&#62;jta&#60;/artifactId&#62; &#60;version&#62;1.1&#60;/version&#62; &#60;/dependency&#62; &#60;dependency&#62; &#60;groupId&#62;xpp3&#60;/groupId&#62; &#60;artifactId&#62;xpp3&#60;/artifactId&#62; &#60;version&#62;1.1.4c&#60;/version&#62; &#60;/dependency&#62; &#60;/dependencies&#62; &#60;/project&#62;</code></pre>
评论 #5275781 未加载
评论 #5275636 未加载
评论 #5275911 未加载
cjbprimeabout 12 years ago
Nice idea!
评论 #5274623 未加载