Set specific serializer for native hessian and hessian rpc protocol (#8238)

This commit is contained in:
ken.lj 2021-07-13 15:31:57 +08:00 committed by GitHub
parent 3548eab668
commit daf6f25137
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 253 additions and 104 deletions

View File

@ -109,7 +109,7 @@
<xmemcached_version>1.3.6</xmemcached_version>
<cxf_version>3.1.15</cxf_version>
<thrift_version>0.12.0</thrift_version>
<hessian_version>4.0.38</hessian_version>
<hessian_version>4.0.51</hessian_version>
<protobuf-java_version>3.6.0</protobuf-java_version>
<javax_annotation-api_version>1.3.2</javax_annotation-api_version>
<servlet_version>3.1.0</servlet_version>

View File

@ -54,6 +54,11 @@
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-native-hession</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>

View File

@ -26,6 +26,7 @@ import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.protocol.AbstractProxyProtocol;
import org.apache.dubbo.rpc.service.GenericService;
import org.apache.dubbo.rpc.support.ProtocolUtils;
import org.apache.dubbo.serialize.hessian.dubbo.Hessian2FactoryInitializer;
import com.caucho.hessian.HessianException;
import com.caucho.hessian.client.HessianConnectionException;
@ -131,6 +132,7 @@ public class HessianProtocol extends AbstractProxyProtocol {
int timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
hessianProxyFactory.setConnectTimeout(timeout);
hessianProxyFactory.setReadTimeout(timeout);
hessianProxyFactory.setSerializerFactory(Hessian2FactoryInitializer.getInstance().getSerializerFactory());
return (T) hessianProxyFactory.create(serviceType, url.setProtocol("http").toJavaURL(), Thread.currentThread().getContextClassLoader());
}
@ -190,7 +192,7 @@ public class HessianProtocol extends AbstractProxyProtocol {
}
try {
skeleton.invoke(request.getInputStream(), response.getOutputStream());
skeleton.invoke(request.getInputStream(), response.getOutputStream(), Hessian2FactoryInitializer.getInstance().getSerializerFactory());
} catch (Throwable e) {
throw new ServletException(e);
}

View File

@ -16,8 +16,10 @@
*/
package org.apache.dubbo.serialize.hessian;
import com.caucho.hessian.io.Hessian2Input;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.serialize.hessian.dubbo.Hessian2FactoryInitializer;
import com.caucho.hessian.io.Hessian2Input;
import java.io.IOException;
import java.io.InputStream;
@ -31,7 +33,7 @@ public class Hessian2ObjectInput implements ObjectInput {
public Hessian2ObjectInput(InputStream is) {
input = new Hessian2Input(is);
input.setSerializerFactory(Hessian2SerializerFactory.INSTANCE);
input.setSerializerFactory(Hessian2FactoryInitializer.getInstance().getSerializerFactory());
}
@Override

View File

@ -16,8 +16,10 @@
*/
package org.apache.dubbo.serialize.hessian;
import com.caucho.hessian.io.Hessian2Output;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.serialize.hessian.dubbo.Hessian2FactoryInitializer;
import com.caucho.hessian.io.Hessian2Output;
import java.io.IOException;
import java.io.OutputStream;
@ -30,7 +32,7 @@ public class Hessian2ObjectOutput implements ObjectOutput {
public Hessian2ObjectOutput(OutputStream os) {
output = new Hessian2Output(os);
output.setSerializerFactory(Hessian2SerializerFactory.INSTANCE);
output.setSerializerFactory(Hessian2FactoryInitializer.getInstance().getSerializerFactory());
}
@Override

View File

@ -16,27 +16,92 @@
*/
package org.apache.dubbo.serialize.hessian;
import org.apache.dubbo.serialize.hessian.serializer.java8.DurationHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.InstantHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.LocalDateHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.LocalDateTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.LocalTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.MonthDayHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.OffsetDateTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.OffsetTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.PeriodHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.YearHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.YearMonthHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.ZoneIdSerializer;
import org.apache.dubbo.serialize.hessian.serializer.java8.ZoneOffsetHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.ZonedDateTimeHandle;
import com.caucho.hessian.io.Deserializer;
import com.caucho.hessian.io.HessianProtocolException;
import com.caucho.hessian.io.Serializer;
import com.caucho.hessian.io.SerializerFactory;
import java.util.HashMap;
import static org.apache.dubbo.serialize.hessian.serializer.java8.Java8TimeSerializer.create;
public class Hessian2SerializerFactory extends SerializerFactory {
public static final SerializerFactory INSTANCE = new Hessian2SerializerFactory();
private HashMap _serializerMap = new HashMap();
private HashMap _deserializerMap = new HashMap();
private Hessian2SerializerFactory() {
public Hessian2SerializerFactory() {
super();
if (isJava8()) {
try {
this.addSerializer(Class.forName("java.time.LocalTime"), create(LocalTimeHandle.class));
this.addSerializer(Class.forName("java.time.LocalDate"), create(LocalDateHandle.class));
this.addSerializer(Class.forName("java.time.LocalDateTime"), create(LocalDateTimeHandle.class));
this.addSerializer(Class.forName("java.time.Instant"), create(InstantHandle.class));
this.addSerializer(Class.forName("java.time.Duration"), create(DurationHandle.class));
this.addSerializer(Class.forName("java.time.Period"), create(PeriodHandle.class));
this.addSerializer(Class.forName("java.time.Year"), create(YearHandle.class));
this.addSerializer(Class.forName("java.time.YearMonth"), create(YearMonthHandle.class));
this.addSerializer(Class.forName("java.time.MonthDay"), create(MonthDayHandle.class));
this.addSerializer(Class.forName("java.time.OffsetDateTime"), create(OffsetDateTimeHandle.class));
this.addSerializer(Class.forName("java.time.ZoneOffset"), create(ZoneOffsetHandle.class));
this.addSerializer(Class.forName("java.time.OffsetTime"), create(OffsetTimeHandle.class));
this.addSerializer(Class.forName("java.time.ZonedDateTime"), create(ZonedDateTimeHandle.class));
} catch (ClassNotFoundException e) {
// ignore
}
}
}
@Override
protected Serializer loadSerializer(Class<?> cl) throws HessianProtocolException {
Serializer serializer = Java8SerializerFactory.INSTANCE.getSerializer(cl);
return serializer != null ? serializer : super.loadSerializer(cl);
public Serializer getSerializer(Class cl) throws HessianProtocolException {
if (isZoneId(cl)) {
return ZoneIdSerializer.getInstance();
}
Object java8Serializer = this._serializerMap.get(cl);
if (java8Serializer != null) {
return (Serializer) java8Serializer;
}
return super.getSerializer(cl);
}
@Override
protected Deserializer loadDeserializer(Class cl) throws HessianProtocolException {
Deserializer deserializer = Java8SerializerFactory.INSTANCE.getDeserializer(cl);
return deserializer != null ? deserializer : super.loadDeserializer(cl);
private static boolean isZoneId(Class cl) {
try {
return isJava8() && Class.forName("java.time.ZoneId").isAssignableFrom(cl);
} catch (ClassNotFoundException e) {
// ignore
}
return false;
}
private static boolean isJava8() {
String javaVersion = System.getProperty("java.specification.version");
return Double.valueOf(javaVersion) >= 1.8;
}
public void addSerializer(Class cl, Serializer serializer) {
this._serializerMap.put(cl, serializer);
}
public void addDeserializer(Class cl, Deserializer deserializer) {
this._deserializerMap.put(cl, deserializer);
}
}

View File

@ -1,88 +0,0 @@
/*
* 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.dubbo.serialize.hessian;
import com.caucho.hessian.io.AbstractSerializerFactory;
import com.caucho.hessian.io.ExtSerializerFactory;
import com.caucho.hessian.io.HessianProtocolException;
import com.caucho.hessian.io.Serializer;
import org.apache.dubbo.serialize.hessian.serializer.java8.DurationHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.InstantHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.LocalDateHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.LocalDateTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.LocalTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.MonthDayHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.OffsetDateTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.OffsetTimeHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.PeriodHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.YearHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.YearMonthHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.ZoneIdSerializer;
import org.apache.dubbo.serialize.hessian.serializer.java8.ZoneOffsetHandle;
import org.apache.dubbo.serialize.hessian.serializer.java8.ZonedDateTimeHandle;
import static org.apache.dubbo.serialize.hessian.serializer.java8.Java8TimeSerializer.create;
public class Java8SerializerFactory extends ExtSerializerFactory {
public static final AbstractSerializerFactory INSTANCE = new Java8SerializerFactory();
private Java8SerializerFactory() {
if (isJava8()) {
try {
this.addSerializer(Class.forName("java.time.LocalTime"), create(LocalTimeHandle.class));
this.addSerializer(Class.forName("java.time.LocalDate"), create(LocalDateHandle.class));
this.addSerializer(Class.forName("java.time.LocalDateTime"), create(LocalDateTimeHandle.class));
this.addSerializer(Class.forName("java.time.Instant"), create(InstantHandle.class));
this.addSerializer(Class.forName("java.time.Duration"), create(DurationHandle.class));
this.addSerializer(Class.forName("java.time.Period"), create(PeriodHandle.class));
this.addSerializer(Class.forName("java.time.Year"), create(YearHandle.class));
this.addSerializer(Class.forName("java.time.YearMonth"), create(YearMonthHandle.class));
this.addSerializer(Class.forName("java.time.MonthDay"), create(MonthDayHandle.class));
this.addSerializer(Class.forName("java.time.OffsetDateTime"), create(OffsetDateTimeHandle.class));
this.addSerializer(Class.forName("java.time.ZoneOffset"), create(ZoneOffsetHandle.class));
this.addSerializer(Class.forName("java.time.OffsetTime"), create(OffsetTimeHandle.class));
this.addSerializer(Class.forName("java.time.ZonedDateTime"), create(ZonedDateTimeHandle.class));
} catch (ClassNotFoundException e) {
// ignore
}
}
}
@Override
public Serializer getSerializer(Class cl) throws HessianProtocolException {
return isZoneId(cl) ? ZoneIdSerializer.getInstance() : super.getSerializer(cl);
}
private static boolean isZoneId(Class cl) {
try {
return isJava8() && Class.forName("java.time.ZoneId").isAssignableFrom(cl);
} catch (ClassNotFoundException e) {
// ignore
}
return false;
}
private static boolean isJava8() {
String javaVersion = System.getProperty("java.specification.version");
return Double.valueOf(javaVersion) >= 1.8;
}
}

View File

@ -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.dubbo.serialize.hessian.dubbo;
import com.caucho.hessian.io.SerializerFactory;
public abstract class AbstractHessian2FactoryInitializer implements Hessian2FactoryInitializer {
private static SerializerFactory SERIALIZER_FACTORY;
@Override
public SerializerFactory getSerializerFactory() {
if (SERIALIZER_FACTORY != null) {
return SERIALIZER_FACTORY;
}
synchronized (this) {
SERIALIZER_FACTORY = createSerializerFactory();
}
return SERIALIZER_FACTORY;
}
protected abstract SerializerFactory createSerializerFactory();
}

View File

@ -0,0 +1,28 @@
/*
* 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.dubbo.serialize.hessian.dubbo;
import org.apache.dubbo.serialize.hessian.Hessian2SerializerFactory;
import com.caucho.hessian.io.SerializerFactory;
public class DefaultHessian2FactoryInitializer extends AbstractHessian2FactoryInitializer {
@Override
protected SerializerFactory createSerializerFactory() {
return new Hessian2SerializerFactory();
}
}

View File

@ -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.dubbo.serialize.hessian.dubbo;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.common.utils.StringUtils;
import com.caucho.hessian.io.SerializerFactory;
@SPI("default")
public interface Hessian2FactoryInitializer {
String WHITELIST = "dubbo.application.hessian2.whitelist";
String ALLOW = "dubbo.application.hessian2.allow";
String DENY = "dubbo.application.hessian2.deny";
ExtensionLoader<Hessian2FactoryInitializer> loader = ExtensionLoader.getExtensionLoader(Hessian2FactoryInitializer.class);
SerializerFactory getSerializerFactory();
static Hessian2FactoryInitializer getInstance() {
String whitelist = ConfigurationUtils.getProperty(WHITELIST);
if (StringUtils.isNotEmpty(whitelist)) {
return loader.getExtension("whitelist");
}
return loader.getDefaultExtension();
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.dubbo.serialize.hessian.dubbo;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.serialize.hessian.Hessian2SerializerFactory;
import com.caucho.hessian.io.SerializerFactory;
/**
* see https://github.com/ebourg/hessian/commit/cf851f5131707891e723f7f6a9718c2461aed826
*/
public class WhitelistHessian2FactoryInitializer extends AbstractHessian2FactoryInitializer {
@Override
public SerializerFactory createSerializerFactory() {
SerializerFactory serializerFactory = new Hessian2SerializerFactory();
String whiteList = ConfigurationUtils.getProperty(WHITELIST);
if ("true".equals(whiteList)) {
serializerFactory.getClassFactory().setWhitelist(true);
String allowPattern = ConfigurationUtils.getProperty(ALLOW);
if (StringUtils.isNotEmpty(allowPattern)) {
serializerFactory.getClassFactory().allow(allowPattern);
}
} else {
serializerFactory.getClassFactory().setWhitelist(false);
String denyPattern = ConfigurationUtils.getProperty(DENY);
if (StringUtils.isNotEmpty(denyPattern)) {
serializerFactory.getClassFactory().deny(denyPattern);
}
}
return serializerFactory;
}
}

View File

@ -0,0 +1,2 @@
default=org.apache.dubbo.serialize.hessian.dubbo.DefaultHessian2FactoryInitializer
whitelist=org.apache.dubbo.serialize.hessian.dubbo.WhitelistHessian2FactoryInitializer

View File

@ -17,6 +17,8 @@
package org.apache.dubbo.serialize.hessian;
import org.apache.dubbo.serialize.hessian.dubbo.Hessian2FactoryInitializer;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.SerializerFactory;
@ -47,7 +49,7 @@ import java.util.Calendar;
*/
public class Java8TimeSerializerTest {
private static SerializerFactory factory = Hessian2SerializerFactory.INSTANCE;
private static SerializerFactory factory = Hessian2FactoryInitializer.getInstance().getSerializerFactory();
private static ByteArrayOutputStream os = new ByteArrayOutputStream();
@Test