我使用的是Maven Project,所以
1。第一步加入Maven Dependency。
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.4.1</version>
</dependency>
2。 然后,加入ant plugin来帮助我们产生protobuf 的java bean。
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<mkdir dir='target/generated-sources' />
<exec executable='protoc'>
<arg value='--java_out=target/generated-sources' />
<arg value='src/main/resources/addressbook.proto' />
</exec>
</tasks>
<sourceRoot>target/generated-sources</sourceRoot>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-antrun-plugin
</artifactId>
<versionRange>[1.3,)</versionRange>
<goals>
<goal>run</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
3。 创建addressbook.proto文件
package tutorial;
option java_package = "com.sampullara.jaxrsprotobuf.tutorial";
option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
4。 运行mvn generate-sources命令来生成AddressBookProtos.java文件。
5。创建rest server端代码AddressBookService.java
package com.sampullara;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import com.sampullara.jaxrsprotobuf.tutorial.AddressBookProtos;
@Path("/person")
public class AddressBookService {
@GET
@Produces("application/x-protobuf")
public AddressBookProtos.Person getPerson() {
return AddressBookProtos.Person.newBuilder()
.setId(1)
.setName("Sam")
.setEmail("sam@sampullara.com")
.addPhone(AddressBookProtos.Person.PhoneNumber.newBuilder()
.setNumber("415-555-1212")
.setType(AddressBookProtos.Person.PhoneType.MOBILE)
.build())
.build();
}
@POST
@Consumes("application/x-protobuf")
@Produces("application/x-protobuf")
public AddressBookProtos.Person reflect(AddressBookProtos.Person person) {
return person;
}
}
6。创建ProtobufProviders.java文件处理protobuf对象序列化。
package com.sampullara;
import com.google.protobuf.GeneratedMessage;
import com.google.protobuf.Message;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.WeakHashMap;
/**
* These providers implement the conversion of protobuf objects to and from their serialized form over the wire.
*
* User: sam
* Date: Dec 27, 2008
* Time: 3:13:17 PM
*/
public class ProtobufProviders {
@Provider
@Consumes("application/x-protobuf")
public static class ProtobufMessageBodyReader implements MessageBodyReader<Message> {
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message.class.isAssignableFrom(type);
}
public Message readFrom(Class<Message> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
try {
Method newBuilder = type.getMethod("newBuilder");
GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type);
return builder.mergeFrom(entityStream).build();
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
}
@Provider
@Produces("application/x-protobuf")
public static class ProtobufMessageBodyWriter implements MessageBodyWriter<Message> {
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message.class.isAssignableFrom(type);
}
private Map<Object, byte[]> buffer = new WeakHashMap<Object, byte[]>();
public long getSize(Message m, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
m.writeTo(baos);
} catch (IOException e) {
return -1;
}
byte[] bytes = baos.toByteArray();
buffer.put(m, bytes);
return bytes.length;
}
public void writeTo(Message m, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
entityStream.write(buffer.remove(m));
}
}
}
7。创建服务器
package com.sampullara;
import java.io.IOException;
import java.net.URI;
import javax.ws.rs.core.UriBuilder;
import com.sun.net.httpserver.HttpServer;
import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
public class Main {
public static final URI BASE_URI = UriBuilder.fromUri("http://localhost/").port(9998).build();
public static HttpServer createServer(URI uri) throws IOException {
ResourceConfig rc = new PackagesResourceConfig("com.sampullara");
return HttpServerFactory.create(uri, rc);
}
}
8。编写客户端代码
package com.sampullara;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import junit.framework.TestCase;
import com.sampullara.ProtobufProviders.ProtobufMessageBodyReader;
import com.sampullara.ProtobufProviders.ProtobufMessageBodyWriter;
import com.sampullara.jaxrsprotobuf.tutorial.AddressBookProtos;
//import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.net.httpserver.HttpServer;
/**
* TODO: Edit this
* <p/>
* User: sam
* Date: Dec 27, 2008
* Time: 5:10:58 PM
*/
public class MainTest extends TestCase {
private HttpServer server;
private WebResource r;
@Override
protected void setUp() throws Exception {
super.setUp();
//start the Grizzly web container and create the client
server = Main.createServer(Main.BASE_URI);
server.start();
ClientConfig cc = new DefaultClientConfig();
cc.getClasses().add(ProtobufMessageBodyReader.class);
cc.getClasses().add(ProtobufMessageBodyWriter.class);
Client c = Client.create(cc);
r = c.resource(Main.BASE_URI);
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
server.stop(0);
}
public void testUsingJerseyClient() {
WebResource wr = r.path("person");
AddressBookProtos.Person p = null;
try {
p = wr.get(AddressBookProtos.Person.class);
} catch (UniformInterfaceException e) {
e.printStackTrace();
}
assertEquals("Sam", p.getName());
AddressBookProtos.Person p2 = wr.type("application/x-protobuf").post(AddressBookProtos.Person.class, p);
assertEquals(p, p2);
}
public void testUsingURLConnection() throws IOException {
AddressBookProtos.Person person;
{
URL url = new URL("http://localhost:9998/person");
URLConnection urlc = url.openConnection();
urlc.setDoInput(true);
urlc.setRequestProperty("Accept", "application/x-protobuf");
person = AddressBookProtos.Person.newBuilder().mergeFrom(urlc.getInputStream()).build();
assertEquals("Sam", person.getName());
}
{
URL url = new URL("http://localhost:9998/person");
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setDoInput(true);
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
urlc.setRequestProperty("Accept", "application/x-protobuf");
urlc.setRequestProperty("Content-Type", "application/x-protobuf");
person.writeTo(urlc.getOutputStream());
AddressBookProtos.Person person2 = AddressBookProtos.Person.newBuilder().mergeFrom(urlc.getInputStream()).build();
assertEquals(person, person2);
}
}
}