Context: I have a web service which return a family with its menbers. A family will always have a father and a mother and no child or multiple childreen. The service is described below by its wsdl.
Purpose: I want to use effectively the Optional from Java 8 and avoid classical way to check null. By classical, I mean the way we were used to accomplish until Java 7.
If I assume that the webservice will always return a family this would be enough:
@Test
public void test1() {
Family f = helloWorldClientImplBean.allFamily();
f.getChildren().stream().filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println(y.getLastName()));
}
I tested and I could see that, as long as I get a family answered by service, it would perfectly works not matter if I have children or not. I mean, in the service implementation below, if I commented the olderSon and youngSon code there will be no null exception at all.
The problem raises when the service return null.
After read several blogs and discussion about it I reach this code which properly check if the return of service was null.
@Test
public void testWorkingButSeemsOdd() {
//Family f = helloWorldClientImplBean.allFamily();
Family f = null; //to make simple the explanation
Optional<Family> optFamily = Optional.ofNullable(f);
if (optFamily.isPresent()) {
optFamily.filter(Objects::nonNull).map(Family::getChildren).get().stream().filter(Objects::nonNull)
.filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println("Optional: " + y.getLastName()));
}
What would be more clean for me would be one of these approaches (all of them are failling but I believe they can show what I have been trying to do):
// here I try to filter if f is not null before mapping
@Test
public void testFilterNonNull() {
Family f = null;
Optional.ofNullable(f).filter(Objects::nonNull).map(Family::getChildren).get().stream().filter(Objects::nonNull)
.filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println(y.getLastName()));
}
I know the next doesn't compile but I guess it is possible to reach something similar
@Test
@Ignore
public void testOptionalNullable() {
Family f = helloWorldClientImplBean.allFamily();
Optional.ofNullable(f).orElse(System.out.println("Family is null")).map(Family::getChildren).get().stream().filter(Objects::nonNull)
.filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println(y.getLastName()));
}
wsdl
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions targetNamespace="http://codenotfound.com/services/helloworld"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://codenotfound.com/services/helloworld"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="HelloWorld">
<wsdl:types>
<schema targetNamespace="http://codenotfound.com/services/helloworld"
xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://codenotfound.com/services/helloworld"
elementFormDefault="qualified" attributeFormDefault="unqualified"
version="1.0">
<element name="family">
<complexType>
<sequence>
<element name="father" type="tns:persontype" minOccurs="1"
maxOccurs="1" />
<element name="mother" type="tns:persontype" minOccurs="1"
maxOccurs="1" />
<element name="children" type="tns:persontype" minOccurs="0"
maxOccurs="unbounded" />
</sequence>
</complexType>
</element>
<complexType name="persontype">
<sequence>
<element name="firstName" type="xsd:string" />
<element name="lastName" type="xsd:string" />
</sequence>
</complexType>
<element name="EmptyParameter" type="tns:voidType" />
<complexType name="voidType">
<sequence />
</complexType>
</schema>
</wsdl:types>
<!-- Message -->
<wsdl:message name="emptyRequest">
<wsdl:part name="emptyParameter" element="tns:EmptyParameter" />
</wsdl:message>
<wsdl:message name="allFamiliesResponse">
<wsdl:part name="allFamiliesResponse" element="tns:family" />
</wsdl:message>
<!-- PortType -->
<wsdl:operation name="allFamilies">
<wsdl:input message="tns:emptyRequest" />
<wsdl:output message="tns:allFamiliesResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<!-- Binding -->
<wsdl:binding name="HelloWorld_Binding" type="tns:HelloWorld_PortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="allFamilies">
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloWorld_Service">
<wsdl:port name="HelloWorld_Port" binding="tns:HelloWorld_Binding">
<soap:address location="http://localhost:9090/cnf/services/helloworld" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
relevant part of service implementation:
@Override
public Family allFamilies(VoidType emptyParameter) {
ObjectFactory factory = new ObjectFactory();
Family result = factory.createFamily();
Persontype father = new Persontype();
father.setFirstName("Jose");
father.setLastName("Pereira");
Persontype mother = new Persontype();
mother.setFirstName("Maria");
mother.setLastName("Pereira");
result.setFather(father);
result.setMother(mother);
Persontype olderSon = new Persontype();
olderSon.setFirstName("John");
olderSon.setLastName("Pereira");
Persontype youngerSon = new Persontype();
youngerSon.setFirstName("Ana");
youngerSon.setLastName("Pereira");
result.getChildren().add(olderSon);
result.getChildren().add(youngerSon);
return result;
}
So, my straight question is: based on my scenario described above with wsdl and its implementation, is the really only way to check if the return from web service is null by using isPresent() in a very similar way we were used to do with classical null checks (if (f != null){...)?