public GetChannelAccountRes getAccounts(GetChannelAccountReq request) {
LawAccountEntity account = new LawAccountEntity();
if(request.getTransactionCode().equals("yyyyyyy") && "1".equals(account.getAccountOwnerType())) {
UserParameter userParameter = userParameterRepository.findByGroupKeyAndKey("xxxxxxx","11111111");
}
return remoteChannelAccountInquiryService.getAccounts(request);
}
Hi, I have this code block. How can I add this userParameter value in request. I want to return something in if statement userParameter value and remoteChannelAccountInquiryService.getAccounts(request) value together.
Java, as a language, doesn't allow multiple return types, i.e. returning two values from the same method. If you want/have to return multiple things from the same method, you'll need to change your return type. The simplest would be to return a Map, i.e.
public Map<GetChannelAccountRes,UserParameter>getAccounts(GetChannelAccountReq request) {
Map<GetChannelAccountRes,UserParameter> map = new HashMap<>();
if (your condition) {
map.put(account, userParameter);
} else {
map.put(account, null); // or some other default value for userParameter
}
return map;
}
but then the caller would either have to iterate the map key/values, or know the key (i.e. the account)
Honestly, the better solution using Java would be to perform the if statement logic in its own method that returns UserParameter and then add the UserParameter as an optional argument to your existing method so that you're always only returning one object.
public UserParameter getUserParameter(GetChannelAccountReq request) {
UserParameter userParameter = null; // or some other default value
if(request.getTransactionCode().equals("yyyyyyy") &&
userParameter = "1".equals(account.getAccountOwnerType())) {
userParameterRepository.findByGroupKeyAndKey("xxxxxxx","11111111");
}
return userParameter;
}
public GetChannelAccountRes getAccounts(GetChannelAccountReq request, UserParameter... userParameter) {
if (userParameter[0] != null) {
// whatever logic that requires both request and userParameter goes here
}
return getChannelAccountRes
}
If the same caller calls both getUserParameter and getAccount, then it would have both objects, which is what I think you intend when you say you wanted both returned together. The varargs (...) parameter in getAccounts is a stylistic matter of taste, and is an array, which is why we check the first index for null. You can do the same thing without using var args like so.
public GetChannelAccountRes getAccounts(GetChannelAccountReq request) {
return getAccounts(request, null); // or some default value for UserParameter intstead of null
}
public GetChannelAccountRes getAccounts(GetChannelAccountReq request, UserParameter... userParameter) {
if (userParameter != null) {
// whatever logic that requires both request and userParameter goes here
}
return getChannelAccountRes
Related
I'm trying to make mock that should return different value if the argument had concrete class. I created tableVerificationService mock object and created these when conditions.
Mockito.when(tableVerificationService.verify(Mockito.any())).thenReturn(true);
Mockito.when(tableVerificationService.verify(Mockito.any(DTable.class))).thenReturn(false);
But now it returns false in any case, even if i pass another from DTable object.
If i change order of these two lines, it will return true in all cases. Is there any way to make correct behavior?
You can use .thenAnswer() or .then() (shorter) to have more control of the returned value.
An example might visualize this better.
Let's assume we want to mock the Java class:
public class OtherService {
public String doStuff(String a) {
return a;
}
}
... and we want to return "even" if the passed String is even and "uneven" otherwise.
By using .then() we get access to the InvocationOnMock and can access the passed argument. This helps to determine the returned value:
class MockitoExampleTest {
#Test
void testMe() {
OtherService otherService = Mockito.mock(OtherService.class);
when(otherService.doStuff(ArgumentMatchers.anyString())).then(invocationOnMock -> {
String passedString = invocationOnMock.getArgument(0);
if (passedString.length() % 2 == 0) {
return "even";
} else {
return "uneven";
}
});
System.out.println(otherService.doStuff("duke")); // even
System.out.println(otherService.doStuff("egg")); // uneven
}
}
With this technique you can check the passed argument and determine if it's your concrete class and then return whatever value you want.
If a 3rd party requests an argument attachments in a method, how may I avoid using an if and break method chaining, knowing that my argument may be null? The method has the following definition.
// import org.jetbrains.annotations.NotNull;
EmailBuilder withAttachments(#NotNull List<Attachment> attachments);
I would prefer NOT using an if condition for .withAttachments, when attachments == null. I know that javascript has method?(), but what is appropriate for java8, or above? In the case where (attachments == null), I don't want to call .withAttachments() at all. But, I don't see syntax comparable to methodA?() like in javascript, or typescript.
return emailBuilder()
.withSubject(email.getSubject())
.withReplyTo(replyAddresses)
.withAttachments(attachments) // This is conditional...based on attachments
.withHeader("X-showheader", email.getShowHeader());
.build();
Would I be required to do this?
EmailBuilder eb = emailBuilder()
.withSubject(email.getSubject())
.withReplyTo(replyAddresses);
if(attachments)
eb = eb.withAttachments(attachments); // This is conditional...based on attachments
eb = eb.withHeader("X-showheader", email.getHeader())
.build;
return eb;
If withAttachments() doesn't allow a null value, then yes, you need if (attachments != null).
But, since builders don't (generally) require a specific order of method calls, you can clean the code up a bit.
EmailBuilder eb = emailBuilder()
.withSubject(email.getSubject())
.withReplyTo(replyAddresses)
.withHeader("X-showheader", email.getHeader());
if (attachments != null)
eb.withAttachments(attachments);
return eb.build();
I'm assuming you can't change the contract of withAttachments to ignore calls with null? You could, upstream wrap attachments in an Optional and then provide an orElse with an empty, but not null, impl of whatever type attachments is, e.g. (assuming attachments is a List):
Optional<...> optionalAttachments = Optional.ofNullable(attachments);
...
.withAttachments(optionalAttachments.orElse(Collections.emptyList())
UPDATE (based on input from comment, hat tip to Andreas)
You could also achieve this with a ternary, e.g.:
.withAttachments(attachments != null ? attachments : Collections.emptyList())
Here is the approach you can use if you can edit or extend the builder.
public class ChainBuilder {
public ChainBuilder ifApplicable(
Supplier<Boolean> filter,
Consumer<ChainBuilder> extension) {
if (filter.get()) {
extension.accept(this);
}
return this;
}
public ChainBuilder withAttribute1(String attribute1) {
//handle store attribute1;
return this;
}
public ChainBuilder withAttribute2(String attribute2) {
//handle store attribute2;
return this;
}
public SomeData build() {
return new SomeDate(); //with the optional attributes
}
}
The client code can chain the methods:
SomeData data = new ChainBuilder()
.withAttribute1("A")
.ifApplicable(() -> false, builder -> builder.withAttribute2("B"))
.build();
It is just an illustration. If you have several conditions, it might make sense to inlcude this into the builder class.
I have a below class in which isValid method is being called.
I am trying to extract few things from Record object in the isValid method. And then I am validating few of those fields. If they are valid, then I am populating the holder map with some additional fields and then I am populating my DataHolder builder class and finally return the DataHolder class back.
If they are not valid, I am returning null.
Below is my class:
public class ProcessValidate extends Validate {
private static final Logger logger = Logger.getInstance(ProcessValidate.class);
#Override
public DataHolder isValid(String processName, Record record) {
Map<String, String> holder = (Map<String, String>) DataUtils.extract(record, "holder");
String deviceId = (String) DataUtils.extract(record, "deviceId");
Integer payId = (Integer) DataUtils.extract(record, "payId");
Long oldTimestamp = (Long) DataUtils.extract(record, "oldTimestamp");
Long newTimestamp = (Long) DataUtils.extract(record, "newTimestamp");
String clientId = (String) DataUtils.extract(record, "clientId");
if (isValidClientIdDeviceId(processName, deviceId, clientId) && isValidPayId(processName, payId)
&& isValidHolder(processName, holder)) {
holder.put("isClientId", (clientId == null) ? "false" : "true");
holder.put("isDeviceId", (clientId == null) ? "true" : "false");
holder.put("abc", (clientId == null) ? deviceId : clientId);
holder.put("timestamp", String.valueOf(oldTimestamp));
DataHolder dataHolder =
new DataHolder.Builder(record).setClientId(clientId).setDeviceId(deviceId)
.setPayId(String.valueOf(payId)).setHolder(holder).setOldTimestamp(oldTimestamp)
.setNewTimestamp(newTimestamp).build();
return dataHolder;
} else {
return null;
}
}
private boolean isValidHolder(String processName, Map<String, String> holder) {
if (MapUtils.isEmpty(holder)) {
// send metrics using processName
logger.logError("invalid holder is coming.");
return false;
}
return true;
}
private boolean isValidpayId(String processName, Integer payId) {
if (payId == null) {
// send metrics using processName
logger.logError("invalid payId is coming.");
return false;
}
return true;
}
private boolean isValidClientIdDeviceId(String processName, String deviceId, String clientId) {
if (Strings.isNullOrEmpty(clientId) && Strings.isNullOrEmpty(deviceId)) {
// send metrics using processName
logger.logError("invalid clientId and deviceId is coming.");
return false;
}
return true;
}
}
Is my isValid method doing lot of things? Can it be broken down in multiple parts? Or is there any better way to write that code?
Also I don't feel great with the code I have in my else block where I return null if record is not valid. I am pretty sure it can written in much better way.
Update:
In my case this is what I was doing. I am calling it like this:
Optional<DataHolder> validatedDataHolder = processValidate.isValid(processName, record);
if (!validatedDataHolder.isPresent()) {
// log error message
}
// otherwise use DataHolder here
So now it means I have to do like this:
boolean validatedDataHolder = processValidate.isValid(processName, record);
if (!validatedDataHolder) {
// log error message
}
// now get DataHolder like this?
Optional<DataHolder> validatedDataHolder = processValidate.getDataHolder(processName, record);
You are correct isValid() is doing too many things. But not only that, when most of us see a method that is called isValid() - we expect a boolean value to be returned. In this case, we're getting back and instance of DataHolder which is counterintuitive.
Try to split the things that you do in the method, for example:
public static boolean isValid(String processName, Record record) {
return isValidClientIdDeviceId(processName, record) &&
isValidPayId(processName, record) &&
isValidHolder(processName, record);
}
and then construct DataHolder in a different method, say:
public static Optional<DataHolder> getDataHolder(String processName, Record record) {
Optional<DataHolder> dataHolder = Optional.empty();
if (isValid(processName, record)) {
dataHolder = Optional.of(buildDataHolder(processName, record));
// ...
}
return dataHolder;
}
It will make your program easier to both read and maintain!
I think things start with naming here.
As alfasin is correctly pointing out, the informal convention is that a method named isValid() should return a boolean value. If you really consider returning a DataHolder; my suggestion would be to change name (and semantics a bit), like this:
DataHolder fetchHolderWithChecks(String processName, Record ...)
And I wouldn't return null - either an Optional; or simply throw an exception. You see, don't you want to tell your user about that error that occured? So when throwing an exception, you would have a mean to provide error messages to higher levels.
On validation itself: I often use something like this:
interface OneAspectValidator {
void check(... // if you want to throw an exception
boolean isValid(... // if you want valid/invalid response
And then various implementations of that interface.
And then, the "validation entry point" would somehow create a list, like
private final static List<OneAspectValidator> validators = ...
to finally iterate that list to validate those aspects one by one.
The nice thing about that approach: you have the code for one kind of validation within one dedicated class; and you can easily enhance your validation; just by creating a new impl class; and adding a corresponding object to that existing list.
I know this might not be directly actionable, but the first thing you should do if you want to clean up this code is to use OO (Object-Orientation). If you are not using OO properly, then there is no point arguing the finer details of OO, like SRP.
What I mean is, I couldn't tell what you code is about. Your classnames are "ProcessValidate" (is that even a thing?), "Record", "DataHolder". That is pretty suspect right there.
The string literals reveal more about the domain ("payId", "deviceId", "clientId") than your identifiers, which is not a good sign.
Your code is all about getting data out of other "objects" instead of asking them to do stuff (the hallmark of OO).
Summary: Try to refactor the code into objects that reflect your domain. Make these objects perform tasks specific to their responsibilities. Try to avoid getting information out of objects. Try to avoid setting information into objects. When that is done, it will be much more clear what SRP is about.
If I'm getting empty session I need to setup some values to play the action class. So, here is the method
public SearchFilters getFilters() {
return (SearchFilters) getSession().get("Filters");
}
I would like to check the session, if it's null, then I need to set the some values over here.
public SearchFilters getFilters() {
if(getSession().get("Filters").equals(null)){
---- //How to set the values and return ?
}
return (SearchFilters) getSession().get("Filters");
}
Use the code:
public SearchFilters getFilters() {
if(getSession().get("Filters") == null){
//How to set the values
getSession().put("Filters", new Filters());
}
// and return.
return (SearchFilters) getSession().get("Filters");
}
assumed you have injected the session into the action via implementing SessionAware.
The value is a free hand object which contains no value, but you could create a constructor to it and pass the value directly.
getSession() will return a new session if an existing session is not found. So you don't need to worry about this one ever returning null. Take note though, there's no get() method under HttpSession, it's getAttribute().
So you can do this:
public SearchFilters getFilters() {
if(getSession().getAttribute("Filters") == null) {
getSession().setAttribute("Filters", new SearchFilters());
}
return (SearchFilters) getSession().getAttribute("Filters");
}
Let's say I'd like to perform the following command:
house.getFloor(0).getWall(WEST).getDoor().getDoorknob();
To avoid a NullPointerException, I'd have to do the following if:
if (house != null && house.getFloor(0) && house.getFloor(0).getWall(WEST) != null
&& house.getFloor(0).getWall(WEST).getDoor() != null) ...
Is there a way or an already existing Utils class that does this more elegantly, let's say something like the following?
checkForNull(house.getFloor(0).getWall(WEST).getDoor().getDoorknob());
In case you can't avoid breaking Law of Demeter (LoD) as stated in the chosen answer, and with Java 8 introducing Optional, it would be probably the best practice to handle nulls in chains of gets such as yours.
The Optional type will enable you to pipe multiple map operations (which contain get calls) in a row. Null checks are automatically handled under the hood.
For example, when the objects aren't initialized, no print() will be made and no Exceptions will be thrown. It all we be handled gently under the hood. When objects are initialized, a print will be made.
System.out.println("----- Not Initialized! -----");
Optional.ofNullable(new Outer())
.map(out -> out.getNested())
.map(nest -> nest.getInner())
.map(in -> in.getFoo())
.ifPresent(foo -> System.out.println("foo: " + foo)); //no print
System.out.println("----- Let's Initialize! -----");
Optional.ofNullable(new OuterInit())
.map(out -> out.getNestedInit())
.map(nest -> nest.getInnerInit())
.map(in -> in.getFoo())
.ifPresent(foo -> System.out.println("foo: " + foo)); //will print!
class Outer {
Nested nested;
Nested getNested() {
return nested;
}
}
class Nested {
Inner inner;
Inner getInner() {
return inner;
}
}
class Inner {
String foo = "yeah!";
String getFoo() {
return foo;
}
}
class OuterInit {
NestedInit nested = new NestedInit();
NestedInit getNestedInit() {
return nested;
}
}
class NestedInit {
InnerInit inner = new InnerInit();
InnerInit getInnerInit() {
return inner;
}
}
class InnerInit {
String foo = "yeah!";
String getFoo() {
return foo;
}
}
So, with your getters chain it will look like this:
Optional.ofNullable(house)
.map(house -> house.getFloor(0))
.map(floorZero -> floorZero.getWall(WEST))
.map(wallWest -> wallWest.getDoor())
.map(door -> wallWest.getDoor())
The return of it will be something like Optional<Door> which will allow you much safer work without worrying of null exceptions.
In order to check a chain of gets for null you may need to call your code from a closure. The closure call code will look like this:
public static <T> T opt(Supplier<T> statement) {
try {
return statement.get();
} catch (NullPointerException exc) {
return null;
}
}
And you call it using the following syntax:
Doorknob knob = opt(() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob());
This code is also type safe and in general works as intended:
Returns an actual value of the specified type if all the objects in the chain are not null.
Returns null if any of the objects in the chain are null.
You may place opt method into shared util class and use it everywhere in your application.
The best way would be to avoid the chain. If you aren't familiar with the Law of Demeter (LoD), in my opinion you should. You've given a perfect example of a message chain that is overly intimate with classes that it has no business knowing anything about.
Law of Demeter: http://en.wikipedia.org/wiki/Law_of_Demeter
You could of course simply wrap the whole expression up in a try-catch block, but that's a bad idea. Something cleaner is the Null object pattern. With that, if your house doesn't have floor 0, it just returns a Floor that acts like a regular Floor, but has no real content; Floors, when asked for Walls they don't have, return similar "Null" Walls, etc, down the line.
Make sure things that can't logically be null are not. For example - a house always has a West wall. In order to avoid such exceptions in state, you can have methods to check whether the state you expect is present:
if (wall.hasDoor()) {
wall.getDoor().etc();
}
This is essentially a null-check, but might not always be.
The point is that you should do something in case you have a null. For example - return or throw an IllegalStateException
And what you shouldn't do - don't catch NullPointerException. Runtime exceptions are not for catching - it is not expected that you can recover from them, nor it is a good practice to rely on exceptions for the logic flow. Imagine that you actually don't expect something to be null, and you catch (and log) a NullPointerException. This will not be very useful information, since many things can be null at that point.
Better solution for me is to use java.util.Optional.map(..) to chain these checks : https://stackoverflow.com/a/67216752/1796826
There is no checkForNull method that you can write that will facilitate this (that's simply not how method invokation and argument evaluation works in Java).
You can break down the chained statements into multiple statements, checking at every step. However, perhaps a better solution is to not have these methods return null in the first place. There is something called the Null Object Pattern that you may want to use instead.
Related questions
How to avoid != null statements in Java?
You could potentially have a generic method like below:
public static <T> void ifPresentThen(final Supplier<T> supplier, final Consumer<T> consumer) {
T value;
try {
value = supplier.get();
} catch (NullPointerException e) {
// Don't consume "then"
return;
}
consumer.accept(value);
}
So now you would be able to do
ifPresentThen(
() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob(),
doorKnob -> doSomething());
implementing nullPointer try/catch with a Supplier you can send it all chain of get
public static <T> T getValue(Supplier<T> getFunction, T defaultValue) {
try {
return getFunction.get();
} catch (NullPointerException ex) {
return defaultValue;
}
}
and then call it in this way.
ObjectHelper.getValue(() -> object1.getObject2().getObject3().getObject4()));
Very old question, but still adding my suggestion:
I would suggest instead of getting the DoorKnob from deep within the House in one method call chain, you should try to let the DoorKnob be provided to this class from the calling code, or by creating a central lookup facility specifically for this purpose (e.g. a DoorKnob service)
Simplified example of design with loose coupling:
class Architect {
FloorContractor floorContractor;
void build(House house) {
for(Floor floor: house.getFloors()) {
floorContractor.build(floor);
}
}
}
class FloorContractor {
DoorMaker doorMaker;
void build(Floor floor) {
for(Wall wall: floor.getWalls()) {
if (wall.hasDoor()) {
doorMaker.build(wall.getDoor());
}
}
}
}
class DoorMaker {
Tool tool;
void build(Door door) {
tool.build(door.getFrame());
tool.build(door.getHinges());
tool.build(door.getDoorKnob());
}
}
// Example
LazyObject.from(curr).apply(A.class, A::getB).apply(B.class, B::getC).apply(C.class, C::getD).to(String.class);
// LazyObject.java
public class LazyObject {
private Object value;
private LazyObject(Object object) {
this.value = object;
}
public <F, T> LazyObject apply(Class<F> type, Function<F, T> func) {
Object v = value;
if (type.isInstance(v)) {
value = func.apply(type.cast(v));
} else {
value = null; // dead here
}
return this;
}
public <T> void accept(Class<T> type, Consumer<T> consumer) {
Object v = value;
if (type.isInstance(v)) {
consumer.accept(type.cast(v));
}
}
public <T> T to(Class<T> type) {
Object v = value;
if (type.isInstance(v)) {
return type.cast(v);
}
return null;
}
public static LazyObject from(Object object) {
return new LazyObject(object);
}
}