Backend Development 14 min read

Design and Implementation of a Java Open Platform SDK

This article explains how to design a modular Java SDK for an open platform, covering HTTP data transmission, flexible JSON/XML serialization adapters, and a simple API client with request/response abstractions, complete with code examples and practical implementation tips.

Architecture Digest
Architecture Digest
Architecture Digest
Design and Implementation of a Java Open Platform SDK

The author presents a step‑by‑step design for a Java open‑platform SDK, dividing the solution into three core modules: a data‑transmission layer, a serialization/deserialization layer, and an application layer that coordinates the two and handles request signing.

Data Transmission – The SDK uses the standard HTTP protocol. An HttpClient interface defines a single post method, and a concrete DefaultHttpClient implementation based on HttpURLConnection performs the request, sets headers, writes the request body, reads the response, and validates the HTTP status.

/**
 * http协议接口
 */
public interface HttpClient {

    /**
     * 执行http post请求
     * @param url
     * @param data
     * @param headers
     */
    String post(String url, byte[] data, Map
> headers) throws HttpClientException;
}
package com.javaobj.sdk.http.impl;

public class DefaultHttpClient implements HttpClient {

    public String post(String url, byte[] data, Map
> headers) throws HttpClientException {
        URL targetUrl = null;
        try {
            targetUrl = new URL(url);
        } catch (MalformedURLException e) {
            throw new HttpClientException("访问的url链接不正确");
        }
        try {
            HttpURLConnection connection = (HttpURLConnection) targetUrl.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");
            if (headers != null) {
                Map
> tmp = new HashMap<>(headers);
                for (Map.Entry
> entry : tmp.entrySet()) {
                    for (String value : entry.getValue()) {
                        connection.setRequestProperty(entry.getKey(), value);
                    }
                }
            }
            connection.connect();
            OutputStream out = connection.getOutputStream();
            out.write(data);
            out.close();
            InputStream in = connection.getInputStream();
            ByteOutputStream body = new ByteOutputStream();
            int ch;
            while ((ch = in.read()) != -1) {
                body.write(ch);
            }
            in.close();
            String responseBody = new String(body.getBytes());
            int statusCode = connection.getResponseCode();
            boolean is2xxSuccessful = statusCode >= 200 && statusCode <= 299;
            boolean is3xxSuccessful = statusCode >= 300 && statusCode <= 399;
            if (!(is2xxSuccessful || is3xxSuccessful)) {
                throw new HttpStatusClientException(statusCode, connection.getResponseMessage(), responseBody);
            }
            return responseBody;
        } catch (IOException e) {
            throw new HttpClientException(e);
        }
    }
}

Serialization / Deserialization – Two simple interfaces, Serializer and Deserializer , are defined. The author provides JSON implementations using Jackson and XML implementations using JAXB. A SerializationAdapter interface extends both and adds a support(String format) method to decide which data format it can handle.

public interface SerializationAdapter extends Serializer, Deserializer {

    /**
     * 判断是否支持数据格式
     */
    boolean support(String format);
}
public class JacksonSerializer implements Serializer {

    private final ObjectMapper objectMapper = new ObjectMapper();

    public JacksonSerializer() {
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    }

    public byte[] serialize(Object obj) {
        try {
            return objectMapper.writeValueAsBytes(obj);
        } catch (JsonProcessingException e) {
            throw new IllegalStateException(e);
        }
    }
}
public class JacksonDeserializer implements Deserializer {

    private final ObjectMapper objectMapper = new ObjectMapper();

    public JacksonDeserializer() {
        objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
    }

    public
T deserialize(byte[] data, Class
clz) {
        try {
            return objectMapper.readValue(data, clz);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }
}
public class JSONSerializationAdapter implements SerializationAdapter {

    private final Serializer serializer;
    private final Deserializer deserializer;

    public JSONSerializationAdapter(Serializer serializer, Deserializer deserializer) {
        this.serializer = serializer;
        this.deserializer = deserializer;
    }

    public JSONSerializationAdapter() {
        this(new JacksonSerializer(), new JacksonDeserializer());
    }

    @Override
    public boolean support(String format) {
        return format != null && Objects.equals(format.toLowerCase(), "json");
    }

    @Override
    public
T deserialize(byte[] data, Class
clz) {
        return deserializer.deserialize(data, clz);
    }

    @Override
    public byte[] serialize(Object obj) {
        return serializer.serialize(obj);
    }
}

Similar JAXB‑based classes ( JAXBSerializer , JAXBDeserializer ) and an XMLSerializationAdapter are provided, demonstrating how additional formats can be plugged in without changing the core SDK.

public class JAXBSerializer implements Serializer {
    @Override
    public byte[] serialize(Object obj) {
        ByteOutputStream outputStream = new ByteOutputStream();
        JAXB.marshal(obj, outputStream);
        return outputStream.getBytes();
    }
}
public class JAXBDeserializer implements Deserializer {
    @Override
    public
T deserialize(byte[] data, Class
clz) {
        return JAXB.unmarshal(new StringReader(new String(data).trim()), clz);
    }
}
public class XMLSerializationAdapter implements SerializationAdapter {

    private final Serializer serializer;
    private final Deserializer deserializer;

    public XMLSerializationAdapter(Serializer serializer, Deserializer deserializer) {
        this.serializer = serializer;
        this.deserializer = deserializer;
    }

    public XMLSerializationAdapter() {
        this(new JAXBSerializer(), new JAXBDeserializer());
    }

    @Override
    public boolean support(String format) {
        return format != null && Objects.equals(format.toLowerCase(), "xml");
    }

    @Override
    public
T deserialize(byte[] data, Class
clz) {
        return deserializer.deserialize(data, clz);
    }

    @Override
    public byte[] serialize(Object obj) {
        return serializer.serialize(obj);
    }
}

Usage Example – A JUnit‑style test shows how to select an adapter based on a format variable, serialize a Person object, and then deserialize it back.

public class SerializationTest {

    @Test
    public void testSerialization(){
        String format = "xml";
        List
adapters = new ArrayList<>();
        adapters.add(new JSONSerializationAdapter());
        adapters.add(new XMLSerializationAdapter());

        Person person = new Person();
        person.setName("霸戈");
        person.setAge(18);

        for(SerializationAdapter adapter : adapters){
            if(adapter.support(format)){
                byte[] data = adapter.serialize(person);
                System.out.println(format + "序列化后的数据:" + new String(data));
                Person person2 = adapter.deserialize(data, Person.class);
                System.out.println(format + "反序列化后的数据:" + person2);
            }
        }
    }
}

API Client Layer – The SDK defines a generic SdkClient interface with an execute method, an abstract AbstractRequest class for request parameters, and an AbstractResponse base class that provides a success check.

public interface SdkClient {
T execute(AbstractRequest
req);
}
public abstract class AbstractRequest
{
    public abstract String getMethod();
    public abstract Map
getApiParams();
    public abstract Class
getResponseClass();
}
public class AbstractResponse {
    private String code;
    private String msg;
    public boolean isSuccess(){
        return Objects.equals(code, "0");
    }
}

The DefaultClient implementation ties everything together: it uses a JSONSerializationAdapter , the DefaultHttpClient , builds a signed URL, sends the request, and deserializes the response.

public class DefaultClient implements SdkClient {

    private SerializationAdapter serializationAdapter = new JSONSerializationAdapter();
    private HttpClient httpClient = new DefaultHttpClient();
    private final String endpoint;
    private final String appid;
    private final String appsecret;

    public DefaultClient(String endpoint, String appid, String appsecret) {
        this.endpoint = endpoint;
        this.appid = appid;
        this.appsecret = appsecret;
    }

    @Override
    public
T execute(AbstractRequest
req) {
        Map
params = req.getApiParams();
        String timestamp = System.currentTimeMillis() + "";
        StringBuilder paramsStr = new StringBuilder();
        Map
treeMap = new TreeMap<>(params);
        for(Map.Entry
entry : treeMap.entrySet()){
            paramsStr.append(entry.getKey()).append(entry.getValue());
        }
        String sign = Md5Util.md5(appsecret + appid + req.getMethod() + req.getVersion() + paramsStr.toString() + appsecret);
        String url = endpoint + "?" +
                "method=" + req.getMethod() +
                "&version=" + req.getVersion() +
                "&timestamp" + timestamp +
                "&sign" + sign +
                "&appid" + appid;
        Map
> headers = new HashMap<>();
        headers.put("Content-type", Collections.singletonList("application/json"));
        byte[] body = serializationAdapter.serialize(req.getApiParams());
        String response = httpClient.post(url, body, headers);
        return serializationAdapter.deserialize(response.getBytes(), req.getResponseClass());
    }
}

Conclusion – The article demonstrates a minimal yet extensible SDK architecture, emphasizing low JDK version compatibility, minimal third‑party dependencies, and the use of plain Java objects for request and response payloads to simplify integration for downstream developers.

backendJavaSDKSerializationOpen PlatformHTTP
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.