Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to solve the problem of dubbo deserialization failure caused by Beanutils

2025-01-20 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "how to solve the problem of dubbo deserialization failure caused by Beanutils". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Scene restoration

   has been tested and found to be really my problem. It's a good thing I didn't throw the pan, otherwise I would have been hit in the face. The error message is as follows:

{"code": "010000", "message": "java.util.HashMap cannot be cast to com.aixiao.inv.common.dto.tax.AddEmployeeDTO$Employee", "data": null}

   is a little confused when he sees this error, and HashMap cannot be converted to AddEmployeeDTO$Employee. Thinking to myself, it doesn't make sense. I copied all the request parameters and did not use Map to pass the parameters at all. After all, I am an old hand. How could I have made such a stupid mistake? As the saying goes, don't panic when you encounter a problem. let's take out our phone and send it to our moments first. it seems to be a little beside the point. Let's take a look at the data transmission of the call chain.

   first web passes the AddEmployeeForm data to the server, and then uses the fromToDTO () method to convert the data into the AddEmployeeDTO required by the Dubbo request. After the Dubbo service puts and receives the AddEmployeeDTO, it converts the data to AddEmployeeXmlReq using EmployeeConvert and then executes the relevant logic.

AddEmployeeForm class @ Datapublic class AddEmployeeForm implements Serializable {/ * employee information list * / private List employees; @ Datapublic static class Employee implements Serializable {/ * name * / private String name; / * Job * / private String job }} FormToDTO () method public T formToDTO (F form, T dto) {/ / copy data BeanUtils.copyProperties (form, dto); / / return data return dto;} AddEmployeeDTOclass @ Datapublic class AddEmployeeDTO implements Serializable {/ * * employee information list * / private List employees @ Data public static class Employee implements Serializable {/ * name * / private String name; / * work * / private String job;}} EmployeeConvert conversion class

EmployeeConvert conversion class, using mapstruct to implement, unused partners can simply understand.

@ Mapperpublic interface EmployeeConvert {EmployeeConvert INSTANCE = Mappers.getMapper (EmployeeConvert.class); AddEmployeeXmlReq dtoToXmlReq (AddEmployeeDTO dto);} AddEmployeeXmlReq class @ Datapublic class AddEmployeeXmlReq implements Serializable {/ * employee information list * / private List employees; @ Datapublic static class Employee implements Serializable {/ * * name * / private String name / * * work * / private String job;}} EmployeeController@RestController@AllArgsConstructorpublic class EmployeeController {private final EmployeeRpcProvider provider; @ PostMapping ("/ employee/add") public ResultVO employeeAdd (@ RequestBody AddEmployeeForm form) {provider.add (formToDTO (form,new AddEmployeeDTO (); return ResultUtil.success () }} EmployeeRpcServiceImpl@Slf4j@Servicepublic class EmployeeRpcServiceImpl implements EmployeeService {@ Override public ResultDTO add (AddEmployeeDTO dto) {log.info ("dubbo-provider-AddEmployeeDTO: {}", JSON.toJSONString (dto)); AddEmployeeXmlReq addEmployeeXmlReq = EmployeeConvert.INSTANCE.dtoToXmlReq (dto); return ResultUtil.success ();}} analyze the cause to determine the exception throw point

   We need to first determine whether the exception is thrown at consumer or provider. The judgment process is simple. We can do the local debug and see where the execution fails. If it is not convenient to debug locally, we can log on the key points. For example, before and after consumer call, before and after provider processing. If you request normal log printing, the order should be:

In this way, you can determine where the exception was thrown by looking at the log.

In fact, it is not so troublesome, because rpc exception interception is done in consumer, so I looked at the log of consumer and knew that it was thrown by provider.

Find the code that went wrong

Since    has found that the problem is caused by provider, it can be seen from the previous call chain that provider will use EmployeeConvert to convert it to AddEmployeeXmlReq when it receives AddEmployeeDTO, so we can print out AddEmployeeDTO to see if the parameter passed by consumer is normal.

   through the log we can see that consumer passed the parameters normally. Then the problem should be that EmployeeConvert converts AddEmployeeDTO to AddEmployeeXmlReq. Since EmployeeConvert is implemented using mapstruct, we can see what the automatically generated transformation class implementation logic looks like.

By looking at the source code,    can see that a List needs to be passed in during the transformation, and this Employee is AddEmployeeDTO.Employee. It may bother me at this time. I obviously passed in AddEmployeeDTO, and there is no Map in the class at all, so why would I throw the exception java.util.HashMap cannot be cast to com.aixiao.inv.common.dto.tax.AddEmployeeDTO$Employee?

Let's Debug and see what happened.

   at this point you will find that what is stored in the received AddEmployeeDTO.employees is not an AddEmployeeDTO$Employee object, but a HashMap. That seems to be the truth. It turns out that dubbo deserialization converts AddEmployeeDTO$Employee to HashMap. This results in a java.util.HashMap cannot be cast to com.aixiao.inv.common.dto.tax.AddEmployeeDTO$Employee exception being thrown.

You think it's over?

Why does    deserialize AddEmployeeDTO$Employee into Map when Dubbo deserializes? When we look back at the log of the printed parameters, there is a warning log that prompts java.lang.ClassNotFoundException:com.aixiao.inv.api.model.form.AddEmployeeForm$Employee. It's a bit strange that we can't find AddEmployeeForm$Employee. Why not AddEmployeeDTO$Employee?

   uses the fromToDTO () method to convert it to AddEmployeeDTO before making a dubbo call. So will the problem arise here? Let's move on to Debug.

   vomited and roared, this is a stone hammer. It turns out that something went wrong during the formToDTO. In the past, the Employee inside the AddEmployeeDTO has become AddEmployeeForm$Employee. That's why provider threw out java.lang.ClassNotFoundException:com.aixiao.inv.api.model.form.AddEmployeeForm$Employee. Take a look at the formToDTO code to see why this happened:

Public T formToDTO (F form, T dto) {/ / copy data BeanUtils.copyProperties (form, dto); / / return data return dto;}

The code in    fromToDTO is very concise, just one method of BeanUtils.copyProperties (), and there is no doubt that it is the culprit. By swimming in the ocean of baidu, I found out why. It turns out that BeanUtils is caused by a shallow copy. The shallow copy simply invokes the set method of the child object and does not copy all the properties. (that is, a memory address referenced), so when translating, point the employees attribute in AddEmployeeDTO to the memory address of AddEmployeeForm's employees. So when the call is made, Dubbo will convert it to Map because it cannot find the corresponding class when deserializing.

Make a brief summary

The problem with    is mainly caused by the shallow copy of BeanUtils. It also causes a chain reaction, resulting in Dubbo deserialization exception and EmployeeConvert conversion exception, and finally throws a java.util.HashMap cannot be cast to com.aixiao.inv.common.dto.tax.AddEmployeeDTO$Employee error message.

Solution method

Now that    knows the cause of the problem, it's easy to solve it. For a single attribute, then the problem of deep copy is not involved, so it is appropriate to use BeanUtils to continue copying. But when it comes to collections, we can do this:

Use foreach to copy simply and rudely.

Use the labmda implementation for transformation.

AddEmployeeDTO dto = new AddEmployeeDTO (); dto.setEmployees (form.getEmployees (). Stream (). Map (tmp-> {AddEmployeeDTO.Employee employee = new AddEmployeeDTO.Employee (); BeanUtils.copyProperties (tmp,employee); return employee;}) .subscription (Collectors.toList ()

Encapsulate a transformation class for transformation.

AddEmployeeDTO dto = new AddEmployeeDTO (); dto.setEmployees (convertList (form.getEmployees (), AddEmployeeDTO.Employee.class)); public List convertList (List source, Class targetClass) {return JSON.parseArray (JSON.toJSONString (source), targetClass);} "how to solve the problem of dubbo deserialization failure caused by Beanutils" ends here, thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report