The Java trap’s entry argument returns the value

The problem background

Normally, entering arguments in Java is not recommended as a return value. In addition to making the code difficult to understand, semantic ambiguity and other problems, there may be traps waiting for you to fall into.

The problem background
Here’s a piece of code:

@Named
public class AService {
private SupplyAssignment localSupply = new SupplyAssignment();
@Inject
private BService bervice;

public List calcSupplyAssignment()
List supplyList = bService.getLocalSupplyList(this.localSupply);

return supplyList;
}
}
In the above code, service A wants to call Service B to get the supplyList, but at the same time, service A wants to modify the status value of localSupply, failing to avoid modifying the calcSupplyAssignment interface (without changing the return type), using localSupply as the input but also as the return value.

Service B code is as follows:

@Named
public class BService {

public List getLocalSupplyList (SupplyAssignment localSupply)
SupplyAssignment supplyAssignment = this.getSupplyAssignment();
// I want localSupply to return after it has been reassigned
localSupply = supplyAssignment;

return supplyList;

}
}
Within the service B code, the input localSupply for service A is passed in, and you want to be reassigned to the supplyAssignment and return the new value. However, this is ineffective.

Question why
Let’s first look at the types of parameter passing in programming languages:

Pass by value refers to passing a copy of the actual arguments to the function when the function is called, so that if the arguments are modified in the function, the actual arguments will not be affected.
Pass by reference means that the address of the actual parameter is directly passed into the function when the function is called, so the modification of the parameter in the function will affect the actual parameter.
Because the Java programming language takes value passing, because Java has no concept of Pointers. That is, the method gets a copy of all parameter values and cannot modify the contents of any parameter variables passed to it.

Therefore, in the above code, when service A invokes service B, the parameter localSupply of service B is actually A copy of localSupply of Service A, both of which, of course, point to the same address object supplyAssignment1.

The problem background

When a re-assignment of the parameter localSupply inside service B is a localSupply = supplyAssignment, it’s really just a new assignment of the parameter localSupply to B, which points to a new address object supplyAssignment2.

 

As can be clearly seen from the figure above, therefore, the localSupply of service A and the parameter localSupply of B have already pointed to different objects, and any modification of the parameter localSupply of B will not affect the original value of localSupply of service A. This is where the problem comes in. You want service B to change the state of service A’s entry and return the changed value to Service A, but it doesn’t work.

The solution
Scenario 1: Do not use entries as return values
Of course, this is the cleanest and easiest to understand, but it can lead to changes in the return types of some interfaces.

Sometimes you do want to do the return value, so look at scenario 2.

Scenario 2: Do not assign new objects to incoming parameters
The solution is to make state changes directly on the participating objects rather than assign new objects. This is the same picture:

 

In this diagram, as long as we keep changing the state value of the supplyAssignment1 to the parameter localSupply of B, the result will be returned to the localSupply of service A. How? Take a look at the following code:

@Named
public class BService {

public List getLocalSupplyList (SupplyAssignment localSupply)

SupplyAssignment supplyAssignment = this.getSupplyAssignment();

// You cannot create a new reference to localSupply, you can only re-assign a property
BeanUtils.copyProperties(supplyAssignment, localSupply);

return supplyList;

}

}
In the above method, we use Spring’s utility class BeanUtils, whose copyProperties method essentially assigns the property value of the supplyAssignment to the property of localSupply. This means that we are modifying a property on localSupply, the parameter to B, not creating a new object.