Skip to content

Commit

Permalink
Provides default (de)serializer by factory method to make it replacea…
Browse files Browse the repository at this point in the history
…ble and customizable.
  • Loading branch information
TeslaCN committed Aug 20, 2020
1 parent 42a63e3 commit dd5e7a3
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 12 deletions.
Expand Up @@ -19,6 +19,7 @@

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.shardingsphere.elasticjob.restful.deserializer.factory.DeserializerFactory;

import java.util.Map;
import java.util.ServiceLoader;
Expand All @@ -32,19 +33,67 @@ public final class RequestBodyDeserializerFactory {

private static final Map<String, RequestBodyDeserializer> REQUEST_BODY_DESERIALIZERS = new ConcurrentHashMap<>();

private static final Map<String, DeserializerFactory> DEFAULT_REQUEST_BODY_DESERIALIZER_FACTORIES = new ConcurrentHashMap<>();

private static final RequestBodyDeserializer MISSING_DESERIALIZER = new RequestBodyDeserializer() {
@Override
public String mimeType() {
throw new UnsupportedOperationException();
}

@Override
public <T> T deserialize(final Class<T> targetType, final byte[] requestBodyBytes) {
throw new UnsupportedOperationException();
}
};

static {
for (RequestBodyDeserializer deserializer : ServiceLoader.load(RequestBodyDeserializer.class)) {
REQUEST_BODY_DESERIALIZERS.put(deserializer.mimeType(), deserializer);
}
for (DeserializerFactory factory : ServiceLoader.load(DeserializerFactory.class)) {
DEFAULT_REQUEST_BODY_DESERIALIZER_FACTORIES.put(factory.mimeType(), factory);
}
}

/**
* Get deserializer for specific HTTP content type.
*
* <p>
* This method will look for a deserializer instance of specific MIME type.
* If deserializer not found, this method would look for deserializer factory by MIME type.
* If it is still not found, the MIME type would be marked as <code>MISSING_DESERIALIZER</code>.
* </p>
*
* <p>
* Some default deserializer will be provided by {@link DeserializerFactory},
* so developers can implement {@link RequestBodyDeserializer} and register it by SPI to override default deserializer.
* </p>
*
* @param contentType HTTP content type
* @return Deserializer
*/
public static RequestBodyDeserializer getRequestBodyDeserializer(final String contentType) {
return REQUEST_BODY_DESERIALIZERS.get(contentType);
RequestBodyDeserializer deserializer = REQUEST_BODY_DESERIALIZERS.get(contentType);
if (null == deserializer) {
synchronized (RequestBodyDeserializerFactory.class) {
if (null == REQUEST_BODY_DESERIALIZERS.get(contentType)) {
deserializer = getRequestBodyDeserializerFromFactories(contentType);
}
}
}
return deserializer != MISSING_DESERIALIZER ? deserializer : null;
}

private static RequestBodyDeserializer getRequestBodyDeserializerFromFactories(final String contentType) {
RequestBodyDeserializer deserializer;
DeserializerFactory factory = DEFAULT_REQUEST_BODY_DESERIALIZER_FACTORIES.get(contentType);
if (null != factory) {
deserializer = factory.createDeserializer();
} else {
deserializer = MISSING_DESERIALIZER;
}
REQUEST_BODY_DESERIALIZERS.put(contentType, deserializer);
return deserializer;
}
}
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.elasticjob.restful.deserializer.factory;

import org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;

/**
* Deserializer factory.
*
* @see RequestBodyDeserializer
* @see org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializerFactory
*/
public interface DeserializerFactory {

/**
* Specify which type would be deserialized by the deserializer created by this factory.
*
* @return MIME type
*/
String mimeType();

/**
* Deserializer factory method.
*
* @return Instance of deserializer
*/
RequestBodyDeserializer createDeserializer();
}
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.elasticjob.restful.deserializer.factory.impl;

import io.netty.handler.codec.http.HttpHeaderValues;
import org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;
import org.apache.shardingsphere.elasticjob.restful.deserializer.factory.DeserializerFactory;
import org.apache.shardingsphere.elasticjob.restful.deserializer.impl.DefaultJsonRequestBodyDeserializer;

public final class DefaultJsonRequestBodyDeserializerFactory implements DeserializerFactory {

@Override
public String mimeType() {
return HttpHeaderValues.APPLICATION_JSON.toString();
}

@Override
public RequestBodyDeserializer createDeserializer() {
return new DefaultJsonRequestBodyDeserializer();
}
}
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.elasticjob.restful.deserializer.factory.impl;

import io.netty.handler.codec.http.HttpHeaderValues;
import org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;
import org.apache.shardingsphere.elasticjob.restful.deserializer.factory.DeserializerFactory;
import org.apache.shardingsphere.elasticjob.restful.deserializer.impl.DefaultTextPlainRequestBodyDeserializer;

public final class DefaultTextPlainRequestBodyDeserializerFactory implements DeserializerFactory {

@Override
public String mimeType() {
return HttpHeaderValues.TEXT_PLAIN.toString();
}

@Override
public RequestBodyDeserializer createDeserializer() {
return new DefaultTextPlainRequestBodyDeserializer();
}
}
Expand Up @@ -19,16 +19,17 @@

import com.google.gson.Gson;
import io.netty.handler.codec.http.HttpHeaderValues;
import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory;
import org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;

import java.nio.charset.StandardCharsets;

/**
* Deserializer for <code>application/json</code>.
*/
public final class JsonRequestBodyDeserializer implements RequestBodyDeserializer {
public final class DefaultJsonRequestBodyDeserializer implements RequestBodyDeserializer {

private final Gson gson = new Gson();
private final Gson gson = GsonFactory.getGson();

@Override
public String mimeType() {
Expand All @@ -37,6 +38,9 @@ public String mimeType() {

@Override
public <T> T deserialize(final Class<T> targetType, final byte[] requestBodyBytes) {
if (0 == requestBodyBytes.length) {
return null;
}
return gson.fromJson(new String(requestBodyBytes, StandardCharsets.UTF_8), targetType);
}
}
Expand Up @@ -24,9 +24,9 @@
import java.text.MessageFormat;

/**
* Deserializer for <code>text/plain</code>.
* Default deserializer for <code>text/plain</code>.
*/
public final class TextPlainRequestBodyDeserializer implements RequestBodyDeserializer {
public final class DefaultTextPlainRequestBodyDeserializer implements RequestBodyDeserializer {

@Override
public String mimeType() {
Expand Down
Expand Up @@ -19,6 +19,7 @@

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.shardingsphere.elasticjob.restful.serializer.factory.SerializerFactory;

import java.util.Map;
import java.util.ServiceLoader;
Expand All @@ -32,19 +33,67 @@ public final class ResponseBodySerializerFactory {

private static final Map<String, ResponseBodySerializer> RESPONSE_BODY_SERIALIZERS = new ConcurrentHashMap<>();

private static final Map<String, SerializerFactory> RESPONSE_BODY_SERIALIZER_FACTORIES = new ConcurrentHashMap<>();

private static final ResponseBodySerializer MISSING_SERIALIZER = new ResponseBodySerializer() {
@Override
public String mimeType() {
throw new UnsupportedOperationException();
}

@Override
public byte[] serialize(final Object responseBody) {
throw new UnsupportedOperationException();
}
};

static {
for (ResponseBodySerializer serializer : ServiceLoader.load(ResponseBodySerializer.class)) {
RESPONSE_BODY_SERIALIZERS.put(serializer.mimeType(), serializer);
}
for (SerializerFactory factory : ServiceLoader.load(SerializerFactory.class)) {
RESPONSE_BODY_SERIALIZER_FACTORIES.put(factory.mimeType(), factory);
}
}

/**
* Get serializer for specific HTTP content type.
*
* <p>
* This method will look for a serializer instance of specific MIME type.
* If serializer not found, this method would look for serializer factory by MIME type.
* If it is still not found, the MIME type would be marked as <code>MISSING_SERIALIZER</code>.
* </p>
*
* <p>
* Some default serializer will be provided by {@link SerializerFactory},
* so developers can implement {@link ResponseBodySerializer} and register it by SPI to override default serializer.
* </p>
*
* @param contentType HTTP content type
* @return Serializer
*/
public static ResponseBodySerializer getResponseBodySerializer(final String contentType) {
return RESPONSE_BODY_SERIALIZERS.get(contentType);
ResponseBodySerializer serializer = RESPONSE_BODY_SERIALIZERS.get(contentType);
if (null == serializer) {
synchronized (ResponseBodySerializerFactory.class) {
if (null == RESPONSE_BODY_SERIALIZERS.get(contentType)) {
serializer = getResponseBodySerializerFromFactories(contentType);
}
}
}
return serializer != MISSING_SERIALIZER ? serializer : null;
}

private static ResponseBodySerializer getResponseBodySerializerFromFactories(final String contentType) {
ResponseBodySerializer serializer;
SerializerFactory factory = RESPONSE_BODY_SERIALIZER_FACTORIES.get(contentType);
if (null != factory) {
serializer = factory.createSerializer();
} else {
serializer = MISSING_SERIALIZER;
}
RESPONSE_BODY_SERIALIZERS.put(contentType, serializer);
return serializer;
}
}
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.elasticjob.restful.serializer.factory;

import org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer;

/**
* Serializer factory.
*
* @see ResponseBodySerializer
* @see org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializerFactory
*/
public interface SerializerFactory {

/**
* Specify which type would be serialized by the serializer created by this factory.
*
* @return MIME type
*/
String mimeType();

/**
* Serializer factory method.
*
* @return Instance of serializer
*/
ResponseBodySerializer createSerializer();
}
@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.elasticjob.restful.serializer.factory.impl;

import io.netty.handler.codec.http.HttpHeaderValues;
import org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer;
import org.apache.shardingsphere.elasticjob.restful.serializer.factory.SerializerFactory;
import org.apache.shardingsphere.elasticjob.restful.serializer.impl.DefaultJsonResponseBodySerializer;

/**
* Factory for {@link DefaultJsonResponseBodySerializer}.
*/
public final class DefaultJsonResponseBodySerializerFactory implements SerializerFactory {

@Override
public String mimeType() {
return HttpHeaderValues.APPLICATION_JSON.toString();
}

@Override
public ResponseBodySerializer createSerializer() {
return new DefaultJsonResponseBodySerializer();
}
}

0 comments on commit dd5e7a3

Please sign in to comment.