add generic reflect type for collection,map,array json (#12732)

This commit is contained in:
suncairong163 2023-07-17 13:28:59 +08:00 committed by GitHub
parent 630e14ae40
commit 2932f09b28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 173 additions and 40 deletions

View File

@ -16,6 +16,7 @@
*/ */
package org.apache.dubbo.metadata.rest; package org.apache.dubbo.metadata.rest;
import org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver;
import org.apache.dubbo.metadata.rest.media.MediaType; import org.apache.dubbo.metadata.rest.media.MediaType;
import java.lang.reflect.Parameter; import java.lang.reflect.Parameter;
@ -39,8 +40,16 @@ public abstract class AbstractNoAnnotatedParameterProcessor implements NoAnnotat
private boolean contentTypeSupport(RestMethodMetadata restMethodMetadata, MediaType mediaType, Class paramType) { private boolean contentTypeSupport(RestMethodMetadata restMethodMetadata, MediaType mediaType, Class paramType) {
// @RequestParam String,number param // @RequestParam String,number param
if (mediaType.equals(MediaType.ALL_VALUE) && (String.class == paramType || paramType.isPrimitive() || Number.class.isAssignableFrom(paramType))) { if (mediaType.equals(MediaType.ALL_VALUE)) {
return true; // jaxrs no annotation param is from http body
if (JAXRSServiceRestMetadataResolver.class.equals(restMethodMetadata.getCodeStyle())) {
return true;
}
// spring mvc no annotation param only is used by text data(string,number)
if (String.class == paramType || paramType.isPrimitive() || Number.class.isAssignableFrom(paramType)) {
return true;
}
} }
Set<String> consumes = restMethodMetadata.getRequest().getConsumes(); Set<String> consumes = restMethodMetadata.getRequest().getConsumes();

View File

@ -18,9 +18,10 @@ package org.apache.dubbo.metadata.rest;
import java.lang.reflect.Parameter; import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
/** /**
* description of service method args info * description of service method args info
*/ */
public class ArgInfo { public class ArgInfo {
/** /**
@ -42,6 +43,11 @@ public class ArgInfo {
*/ */
private Class paramType; private Class paramType;
/**
* param actual Type(collection,map,array)
*/
private Type actualType;
/** /**
* param name * param name
*/ */
@ -64,6 +70,7 @@ public class ArgInfo {
public ArgInfo(int index, Parameter parameter) { public ArgInfo(int index, Parameter parameter) {
this(index, parameter.getName(), parameter.getType()); this(index, parameter.getName(), parameter.getType());
this.actualType = parameter.getParameterizedType();
} }
public ArgInfo() { public ArgInfo() {
@ -152,6 +159,10 @@ public class ArgInfo {
return this; return this;
} }
public Type actualReflectType() {
return actualType;
}
@Override @Override
public String toString() { public String toString() {
return "ArgInfo{" + return "ArgInfo{" +

View File

@ -40,6 +40,7 @@ import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodecManager;
import org.apache.dubbo.rpc.protocol.rest.util.HttpHeaderUtil; import org.apache.dubbo.rpc.protocol.rest.util.HttpHeaderUtil;
import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil; import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil;
import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -100,9 +101,10 @@ public class RestInvoker<T> extends AbstractInvoker<T> {
} else if (responseCode >= 500) { } else if (responseCode >= 500) {
responseFuture.completeExceptionally(new RemoteServerInternalException(r.getMessage())); responseFuture.completeExceptionally(new RemoteServerInternalException(r.getMessage()));
} else if (responseCode < 400) { } else if (responseCode < 400) {
mediaType = MediaTypeUtil.convertMediaType(restMethodMetadata.getReflectMethod().getReturnType(), r.getContentType()); Method reflectMethod = restMethodMetadata.getReflectMethod();
mediaType = MediaTypeUtil.convertMediaType(reflectMethod.getReturnType(), r.getContentType());
Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(), Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(),
restMethodMetadata.getReflectMethod().getReturnType(), mediaType); reflectMethod.getReturnType(), reflectMethod.getGenericReturnType(), mediaType);
appResponse.setValue(value); appResponse.setValue(value);
// resolve response attribute & attachment // resolve response attribute & attachment
HttpHeaderUtil.parseResponseHeader(appResponse, r); HttpHeaderUtil.parseResponseHeader(appResponse, r);

View File

@ -28,7 +28,6 @@ import org.apache.dubbo.rpc.protocol.rest.request.RequestFacade;
import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil; import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil;
/** /**
* body param parse * body param parse
*/ */
@ -43,7 +42,7 @@ public class BodyProviderParamParser extends ProviderParamParser {
try { try {
String contentType = parseContext.getRequestFacade().getHeader(RestHeaderEnum.CONTENT_TYPE.getHeader()); String contentType = parseContext.getRequestFacade().getHeader(RestHeaderEnum.CONTENT_TYPE.getHeader());
MediaType mediaType = MediaTypeUtil.convertMediaType(argInfo.getParamType(), contentType); MediaType mediaType = MediaTypeUtil.convertMediaType(argInfo.getParamType(), contentType);
Object param = HttpMessageCodecManager.httpMessageDecode(request.getInputStream(), argInfo.getParamType(), mediaType); Object param = HttpMessageCodecManager.httpMessageDecode(request.getInputStream(), argInfo.getParamType(), argInfo.actualReflectType(), mediaType);
parseContext.setValueByIndex(argInfo.getIndex(), param); parseContext.setValueByIndex(argInfo.getIndex(), param);
} catch (Throwable e) { } catch (Throwable e) {
throw new ParamParseException("dubbo rest protocol provider body param parser error: " + e.getMessage()); throw new ParamParseException("dubbo rest protocol provider body param parser error: " + e.getMessage());

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.rpc.protocol.rest.exception.UnSupportContentTypeExceptio
import org.apache.dubbo.rpc.protocol.rest.pair.MessageCodecResultPair; import org.apache.dubbo.rpc.protocol.rest.pair.MessageCodecResultPair;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.Set; import java.util.Set;
public class HttpMessageCodecManager { public class HttpMessageCodecManager {
@ -30,14 +31,14 @@ public class HttpMessageCodecManager {
FrameworkModel.defaultModel().getExtensionLoader(HttpMessageCodec.class).getSupportedExtensionInstances(); FrameworkModel.defaultModel().getExtensionLoader(HttpMessageCodec.class).getSupportedExtensionInstances();
public static Object httpMessageDecode(byte[] body, Class<?> type, MediaType mediaType) throws Exception { public static Object httpMessageDecode(byte[] body, Class<?> type, Type actualType, MediaType mediaType) throws Exception {
if (body == null || body.length == 0) { if (body == null || body.length == 0) {
return null; return null;
} }
for (HttpMessageCodec httpMessageCodec : httpMessageCodecs) { for (HttpMessageCodec httpMessageCodec : httpMessageCodecs) {
if (httpMessageCodec.contentTypeSupport(mediaType, type) || typeJudge(mediaType, type, httpMessageCodec)) { if (httpMessageCodec.contentTypeSupport(mediaType, type) || typeJudge(mediaType, type, httpMessageCodec)) {
return httpMessageCodec.decode(body, type); return httpMessageCodec.decode(body, type,actualType);
} }
} }
throw new UnSupportContentTypeException("UnSupport content-type :" + mediaType.value); throw new UnSupportContentTypeException("UnSupport content-type :" + mediaType.value);

View File

@ -17,8 +17,11 @@
package org.apache.dubbo.rpc.protocol.rest.message; package org.apache.dubbo.rpc.protocol.rest.message;
public interface HttpMessageDecode<InputStream>{ import java.lang.reflect.Type;
public interface HttpMessageDecode<InputStream> {
Object decode(InputStream body, Class<?> targetType,Type actualTYpe) throws Exception;
Object decode(InputStream body, Class<?> targetType) throws Exception;
} }

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.metadata.rest.media.MediaType;
import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec; import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
/** /**
* body type is byte array * body type is byte array
@ -31,7 +32,7 @@ public class ByteArrayCodec implements HttpMessageCodec<byte[], OutputStream> {
@Override @Override
public Object decode(byte[] body, Class<?> targetType) throws Exception { public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
return body; return body;
} }

View File

@ -23,14 +23,15 @@ import org.apache.dubbo.metadata.rest.media.MediaType;
import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec; import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
import org.apache.dubbo.rpc.protocol.rest.message.MediaTypeMatcher; import org.apache.dubbo.rpc.protocol.rest.message.MediaTypeMatcher;
import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils; import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
import javax.ws.rs.core.Response;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
* body is json * body is json
*/ */
@Activate("json") @Activate("json")
public class JsonCodec implements HttpMessageCodec<byte[], OutputStream> { public class JsonCodec implements HttpMessageCodec<byte[], OutputStream> {
@ -39,12 +40,15 @@ public class JsonCodec implements HttpMessageCodec<byte[], OutputStream> {
static { static {
unSupportClasses.add(byte[].class); unSupportClasses.add(byte[].class);
unSupportClasses.add(String.class); unSupportClasses.add(String.class);
unSupportClasses.add(Response.class); }
public static void addUnSupportClass(Class<?> unSupportClass) {
unSupportClasses.add(unSupportClass);
} }
@Override @Override
public Object decode(byte[] body, Class<?> targetType) throws Exception { public Object decode(byte[] body, Class<?> targetType, Type actualType) throws Exception {
return DataParseUtils.jsonConvert(targetType, body); return DataParseUtils.jsonConvert(actualType, body);
} }
@Override @Override

View File

@ -26,6 +26,7 @@ import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -39,8 +40,7 @@ public class MultiValueCodec implements HttpMessageCodec<byte[], OutputStream> {
@Override @Override
public Object decode(byte[] body, Class<?> targetType) throws Exception { public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
// TODO java bean get set convert
Object map = DataParseUtils.multipartFormConvert(body,targetType); Object map = DataParseUtils.multipartFormConvert(body,targetType);
Map valuesMap = (Map) map; Map valuesMap = (Map) map;
if (Map.class.isAssignableFrom(targetType)) { if (Map.class.isAssignableFrom(targetType)) {

View File

@ -26,15 +26,18 @@ import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@Activate(onClass="javax.ws.rs.core.Response") @Activate(onClass = "javax.ws.rs.core.Response")
public class ResteasyResponseCodec implements HttpMessageCodec<byte[], OutputStream> { public class ResteasyResponseCodec implements HttpMessageCodec<byte[], OutputStream> {
private Class<?> responseClass; private Class<?> responseClass;
public ResteasyResponseCodec(){
public ResteasyResponseCodec() {
try { try {
responseClass = ClassUtils.forName("javax.ws.rs.core.Response"); responseClass = ClassUtils.forName("javax.ws.rs.core.Response");
JsonCodec.addUnSupportClass(responseClass);
} catch (Exception exception) { } catch (Exception exception) {
responseClass = null; responseClass = null;
} }
@ -56,7 +59,7 @@ public class ResteasyResponseCodec implements HttpMessageCodec<byte[], OutputStr
} }
@Override @Override
public Object decode(byte[] body, Class<?> targetType) throws Exception { public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
if (null == body || body.length == 0) { if (null == body || body.length == 0) {
return null; return null;
} }

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.metadata.rest.media.MediaType;
import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec; import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/** /**
@ -32,7 +33,7 @@ public class StringCodec implements HttpMessageCodec<byte[], OutputStream> {
@Override @Override
public Object decode(byte[] body, Class<?> targetType) throws Exception { public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
if (body == null || body.length == 0) { if (body == null || body.length == 0) {
return null; return null;
} }

View File

@ -24,6 +24,7 @@ import org.apache.dubbo.rpc.protocol.rest.message.MediaTypeMatcher;
import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils; import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/** /**
@ -33,7 +34,7 @@ import java.nio.charset.StandardCharsets;
public class TextCodec implements HttpMessageCodec<byte[], OutputStream> { public class TextCodec implements HttpMessageCodec<byte[], OutputStream> {
@Override @Override
public Object decode(byte[] body, Class<?> targetType) throws Exception { public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
return DataParseUtils.stringTypeConvert(targetType, new String(body, StandardCharsets.UTF_8)); return DataParseUtils.stringTypeConvert(targetType, new String(body, StandardCharsets.UTF_8));
} }

View File

@ -32,6 +32,7 @@ import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXSource;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Type;
/** /**
* body content-type is xml * body content-type is xml
@ -41,7 +42,7 @@ public class XMLCodec implements HttpMessageCodec<byte[], OutputStream> {
@Override @Override
public Object decode(byte[] body, Class<?> targetType) throws Exception { public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParserFactory spf = SAXParserFactory.newInstance();

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.common.utils.StringUtils;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -151,7 +152,7 @@ public class DataParseUtils {
} }
public static Object jsonConvert(Class targetType, byte[] body) throws Exception { public static Object jsonConvert(Type targetType, byte[] body) throws Exception {
return JsonUtils.toJavaObject(new String(body, StandardCharsets.UTF_8), targetType); return JsonUtils.toJavaObject(new String(body, StandardCharsets.UTF_8), targetType);
} }

View File

@ -31,6 +31,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
@Path("/demoService") @Path("/demoService")
public interface DemoService { public interface DemoService {
@ -128,4 +129,24 @@ public interface DemoService {
@Consumes({MediaType.APPLICATION_JSON}) @Consumes({MediaType.APPLICATION_JSON})
User noBodyArg(User user); User noBodyArg(User user);
@POST
@Path("/list")
List<User> list(List<User> users);
@POST
@Path("/set")
Set<User> set(Set<User> users);
@POST
@Path("/array")
User[] array(User[] users);
@POST
@Path("/stringMap")
Map<String, User> stringMap(Map<String,User> userMap);
@POST
@Path("/map")
Map<User, User> userMap(Map<User,User> userMap);
} }

View File

@ -30,6 +30,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
@Path("/demoService") @Path("/demoService")
public class DemoServiceImpl implements DemoService { public class DemoServiceImpl implements DemoService {
@ -91,7 +92,7 @@ public class DemoServiceImpl implements DemoService {
} }
@Override @Override
public List<String> testMapForm(MultivaluedMap<String,String> params) { public List<String> testMapForm(MultivaluedMap<String, String> params) {
return params.get("form"); return params.get("form");
} }
@ -120,7 +121,7 @@ public class DemoServiceImpl implements DemoService {
@Path("/noIntHeader") @Path("/noIntHeader")
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
@Override @Override
public int noIntHeader(@HeaderParam("header")int header) { public int noIntHeader(@HeaderParam("header") int header) {
return header; return header;
} }
@ -128,7 +129,7 @@ public class DemoServiceImpl implements DemoService {
@Path("/noIntParam") @Path("/noIntParam")
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
@Override @Override
public int noIntParam(@QueryParam("header")int header) { public int noIntParam(@QueryParam("header") int header) {
return header; return header;
} }
@ -156,4 +157,31 @@ public class DemoServiceImpl implements DemoService {
public static Map<String, Object> getAttachments() { public static Map<String, Object> getAttachments() {
return context; return context;
} }
@Override
public List<User> list(List<User> users) {
return users;
}
@Override
public Set<User> set(Set<User> users) {
return users;
}
@Override
public User[] array(User[] users) {
return users;
}
@Override
public Map<String, User> stringMap(Map<String, User> userMap) {
return userMap;
}
@Override
public Map<User, User> userMap(Map<User, User> userMap) {
return userMap;
}
} }

View File

@ -37,7 +37,7 @@ public class HttpMessageCodecManagerTest {
HttpMessageCodecManager.httpMessageEncode(byteArrayOutputStream, HttpMessageCodecManager.httpMessageEncode(byteArrayOutputStream,
registrationResult, null, MediaType.TEXT_XML, null); registrationResult, null, MediaType.TEXT_XML, null);
Object o = HttpMessageCodecManager.httpMessageDecode(byteArrayOutputStream.toByteArray(), RegistrationResult.class, MediaType.TEXT_XML); Object o = HttpMessageCodecManager.httpMessageDecode(byteArrayOutputStream.toByteArray(), RegistrationResult.class, RegistrationResult.class, MediaType.TEXT_XML);
Assertions.assertEquals(registrationResult, o); Assertions.assertEquals(registrationResult, o);

View File

@ -59,8 +59,10 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import static org.apache.dubbo.remoting.Constants.SERVER_KEY; import static org.apache.dubbo.remoting.Constants.SERVER_KEY;
@ -616,23 +618,23 @@ class JaxrsRestProtocolTest {
@Test @Test
void testGetInvoker() { void testGetInvoker() {
Assertions.assertDoesNotThrow(()->{ Assertions.assertDoesNotThrow(() -> {
URL exportUrl = URL.valueOf("rest://127.0.0.1:" + availablePort + "/rest?interface=org.apache.dubbo.rpc.protocol.rest.rest.TestGetInvokerService"); URL exportUrl = URL.valueOf("rest://127.0.0.1:" + availablePort + "/rest?interface=org.apache.dubbo.rpc.protocol.rest.rest.TestGetInvokerService");
TestGetInvokerService server = new TestGetInvokerServiceImpl(); TestGetInvokerService server = new TestGetInvokerServiceImpl();
URL url = this.registerProvider(exportUrl, server, DemoService.class); URL url = this.registerProvider(exportUrl, server, DemoService.class);
Exporter<TestGetInvokerService> exporter = protocol.export(proxy.getInvoker(server, TestGetInvokerService.class, url)); Exporter<TestGetInvokerService> exporter = protocol.export(proxy.getInvoker(server, TestGetInvokerService.class, url));
TestGetInvokerService invokerService = this.proxy.getProxy(protocol.refer(TestGetInvokerService.class, url)); TestGetInvokerService invokerService = this.proxy.getProxy(protocol.refer(TestGetInvokerService.class, url));
String invoker = invokerService.getInvoker(); String invoker = invokerService.getInvoker();
Assertions.assertEquals("success", invoker); Assertions.assertEquals("success", invoker);
exporter.unexport(); exporter.unexport();
}); });
} }
@Test @Test
@ -689,6 +691,37 @@ class JaxrsRestProtocolTest {
exporter.unexport(); exporter.unexport();
} }
@Test
void testCollectionResult() {
DemoService server = new DemoServiceImpl();
URL url = this.registerProvider(exportUrl, server, DemoService.class);
URL nettyUrl = url.addParameter(SERVER_KEY, "netty");
Exporter<DemoService> exporter = protocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
Assertions.assertEquals(User.getInstance(), demoService.list(Arrays.asList(User.getInstance())).get(0));
HashSet<User> objects = new HashSet<>();
objects.add(User.getInstance());
Assertions.assertEquals(User.getInstance(), new ArrayList<>(demoService.set(objects)).get(0));
Assertions.assertEquals(User.getInstance(), demoService.array(objects.toArray(new User[0]))[0]);
Map<String, User> map = new HashMap<>();
map.put("map", User.getInstance());
Assertions.assertEquals(User.getInstance(), demoService.stringMap(map).get("map"));
Map<User, User> maps = new HashMap<>();
maps.put(User.getInstance(), User.getInstance());
Assertions.assertEquals(User.getInstance(), demoService.userMap(maps).get(User.getInstance()));
exporter.unexport();
}
private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) { private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) {
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass); ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
ProviderModel providerModel = new ProviderModel( ProviderModel providerModel = new ProviderModel(

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.rpc.protocol.rest; package org.apache.dubbo.rpc.protocol.rest;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
/** /**
* User Entity * User Entity
@ -63,6 +64,19 @@ public class User implements Serializable {
return user; return user;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age);
}
@Override @Override
public String toString() { public String toString() {
return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';