Enterprise Integration Zone is brought to you in partnership with:

Milan has posted 4 posts at DZone. View Full User Profile

5 Techniques for Creating Java Web Services from WSDL

04.29.2008
| 351044 views |
  • submit to reddit

In this article, I will implement a simple Document/Literal web service, from an existing WSDL file, using three different databinding frameworks and two low-level approaches. The goal is to compare the frameworks, mainly from the ease-of-use perspective. For demo purposes, I have chosen NetBeans IDE 6.1 with its standard Web Service functionality and its Axis2 plugin. The standard Web Service support in NetBeans IDE is based on the JAX-WS stack. These are the frameworks used in this article:

  • JAX-WS 2.1 (Java artifacts generated with wsimport)
  • JAX-WS 2.1 (Provider API implementation)
  • Axis with ADB (Axis Databinding)
  • AXIOM (Axis Object Model)
  • Axis with Xmlbeans

WSDL File

Initially I wanted to use the simple AddNumbers.html file from JAX-WS2.1 examples but I encountered problems related to Java artifacts generation with both Axis ADB and Xmlbeans. After some investigation I found the reason: ADB and Xmlbeans have problems generating Java artifacts if (1) wsdl namespace and schema namespace are identical and (2) the <wsdl:message> representing <wsdl:fault> has the same name as schema element. Though the wsdl file is WS-I compliant, the 2 databinding technologies failed. I also tested JiBX databinding, without success. To go on I had to modify the wsdl file a little: AddNumbers.wsdl (the schema namespace is changed).

Note: Even after this change the JiBX databinding failed to generate Java classes (I used the Axis2 wsdl4j task) so I decided not to use JiBX in this article.

JAX-WS 2.1 (Java artifacts generated with wsimport)

For this purpose I've created new web application project and used Web Service Wrom WSDL wizard in Web Services category. The implementation was easy:
@WebService(serviceName = "AddNumbersService", portName = "AddNumbersPort", endpointInterface = "org.example.duke.AddNumbersPortType",
targetNamespace = "http://duke.example.org", wsdlLocation = "WEB-INF/wsdl/AddNumbersImpl/AddNumbers.wsdl")
public class AddNumbersImpl implements AddNumbersPortType {

public int addNumbers(int arg0, int arg1) throws AddNumbersFault {
int result = arg0+arg1;
if (result < 0) {
org.example.duke.xsd.AddNumbersFault fault = new org.example.duke.xsd.AddNumbersFault();
fault.setMessage("the result is negative");
fault.setFaultInfo("negative result: "+result);
throw new AddNumbersFault("error", fault);
} else {
return result;
}
}

public void oneWayInt(int arg0) {
System.out.println("JAX-WS: oneWayInt request "+arg0);
}

}

 

The implementation is really easy as wsimport by default generates Web Service (SEI class) methods in Wrapping Style mode, which means for requests, responses represented by a sequence of xsd primitive types, the WS method works directly with Java primitive types. For that reason JAX-WS uses the @javax.xml.ws.RequestWrapper and @javax.xml.ws.ResponseWrapper annotations in generated SEI class. The most complex, but not difficult, was the implementation of AddNumbersFault: the exception is thrown when the result is negative. NetBeans Code Completion helped me greatly in this area.

 

JAX-WS 2.1 (Provider API implementation)

To implement the low level approach supporting by JAX-WS 2.1. I used the standard Web Service from WSDL wizard, and I checked the Use Provider checkbox (new NetBeans IDE 6.1 feature). The implementation requires to know the structure of XML request and XML response. See that XML DOM API is used to process the request, while the response is written directly as plain XML text. The hardiest part for me was to implement the Fault correctly.
@ServiceMode(value = javax.xml.ws.Service.Mode.PAYLOAD)
@WebServiceProvider(serviceName = "AddNumbersService", portName = "AddNumbersPort",
targetNamespace = "http://duke.example.org", wsdlLocation = "WEB-INF/wsdl/AddNumbersImpl/AddNumbers.wsdl")
public class AddNumbersImpl implements javax.xml.ws.Provider<javax.xml.transform.Source> {

public javax.xml.transform.Source invoke(javax.xml.transform.Source source) {
try {
DOMResult dom = new DOMResult();
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.transform(source, dom);
Node node = dom.getNode();
Node root = node.getFirstChild();
Node first = root.getFirstChild();
int number1 = Integer.decode(first.getFirstChild().getNodeValue());
Node second = first.getNextSibling();
int number2 = Integer.decode(second.getFirstChild().getNodeValue());
int result = number1+number2;
if (result < 0) {
return getFault(result);
} else {
return getResponse(result);
}
} catch(Exception e) {
throw new RuntimeException("Error in provider endpoint", e);
}
}

private Source getResponse(int result) {
String body =
"<ns:addNumbersResponse xmlns:ns=\"http://duke.example.org/xsd\"><ns:return>"
+result
+"</ns:return></ns:addNumbersResponse>";
Source source = new StreamSource(
new ByteArrayInputStream(body.getBytes()));
return source;
}

private Source getFault(int result) {
String body =
"<nsf:Fault xmlns:nsf=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+"<faultcode>nsf:Server</faultcode>"
+"<faultstring>error</faultstring>"
+"<detail>"
+"<ns:AddNumbersFault xmlns:ns=\"http://duke.example.org/xsd\">"
+"<ns:faultInfo>negative result "+result+"</ns:faultInfo>"
+"<ns:message>the result is negative</ns:message>"
+"</ns:AddNumbersFault>"
+"</detail>"
+"</nsf:Fault>";
Source source = new StreamSource(
new ByteArrayInputStream(body.getBytes()));
return source;
}
}
Another option is to use JAXB data binding to process the request and/or to generate the response. JAXB can be used comfortably with Provider API. Advantage of this approach is that implementation code works with JAXB classes generated from schema file rather than with low level DOM objects. The dark side is that JAXB classes (derived from schema file) should be generated in advance. I just copied the content of org.example.duke.xsd package from previous example:
    public javax.xml.transform.Source invoke(javax.xml.transform.Source source) {
try {
JAXBContext jc = JAXBContext.newInstance( "org.example.duke.xsd" );
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<AddNumbers> requestEl = (JAXBElement) unmarshaller.unmarshal(source);
AddNumbers addNum = requestEl.getValue();
int result = addNum.getArg0()+addNum.getArg1();
if (result < 0) {
return getFault(result);
} else {
AddNumbersResponse response = new AddNumbersResponse();
response.setReturn(result);
JAXBElement<AddNumbersResponse> responseEl = new ObjectFactory().createAddNumbersResponse(response);
return new JAXBSource(jc, responseEl);
}
} catch (JAXBException e) {
throw new RuntimeException("Error in provider endpoint", e);
}
}

 

Note: The biggest advantage of JAX-WS Provider/Dispatcher API is the ability to implement/consume web services even for the cases where wsimport fails (e.g. RPC/Encoded WSDL). See Accessing Google Web Service using JAX-WS. Another option would be to implement the invoke method with SOAPMessage parameter instead of javax.xml.transform.Source. This is more convenient than DOM but requires to work with entire SOAP message rather than with SOAP payload.

 

Axis with ADB (Axis Databinding)

To implement web service using Axis ADB I installed the Axis2 plugin on the top of NetBeans IDE 6.1. To set up NetBeans IDE with Axis2 support see the tutorial: Creating Apache Axis2 Web Services on NetBeans IDE. To create web service from wsdl file I used the Axis Web Service from WSDL wizard from Web Services category. In the wizard, the wsdl file can be selected in Name and Location Panel and ADB databinding stack in Code Generator Options panel -> Databinding Technology combo box. The Axis2 wsdl4j utility is called from the wizard, and the skeleton class for web service is generated to implement. The implementation is fairly simple, intuitive and straightforward. The code completions helps a lot :
public class AddNumbersImpl implements AddNumbersServiceSkeletonInterface {

public AddNumbersResponse2 addNumbers(AddNumbers1 addNumbers0) throws AddNumbersFault {
int result = addNumbers0.getAddNumbers().getArg0() + addNumbers0.getAddNumbers().getArg1();
if (result < 0) {
AddNumbersFault fault = new AddNumbersFault();
AddNumbersFault0 faultMessage = new AddNumbersFault0();
org.example.duke.xsd.AddNumbersFault fDetail = new org.example.duke.xsd.AddNumbersFault();
fDetail.setFaultInfo("negative result "+result);fDetail.setMessage("the result is negative");
faultMessage.setAddNumbersFault(fDetail);
fault.setFaultMessage(faultMessage);
throw fault;
} else {
AddNumbersResponse resp = new AddNumbersResponse();
resp.set_return(result);
AddNumbersResponse2 response = new AddNumbersResponse2();
response.setAddNumbersResponse(resp);
return response;
}
}

public void oneWayInt(org.example.duke.xsd.OneWayInt3 oneWayInt2) {
try {
OMElement request = oneWayInt2.getOMElement(OneWayInt3.MY_QNAME, OMAbstractFactory.getOMFactory());
System.out.println("ADB:oneWayInt request: "+request);
} catch (ADBException ex) {
ex.printStackTrace();
}
}
}

 

Note: Axis2 doesn't use the Wrapping Style, so the parameter of AddNumbers method, in skeleton class, is AddNumbers1 object instead of 2 int parameters (I didn't find if axis2 enables to set up wrapping style).

 

AXIOM (AxisObject Model)

This is a low level technique, similar to JAX-WS Provider/Dispatcherer API. Working with OM nodes and elemens is more comfortable comparing to DOM but less comparing to ADB or JAXB. I'd compare it to working with SAAJ API. The imlementation is also quite straightforward but requires the knowledge of AXIOM API. The skeleton class can be generated by Axis Service from Wsdl wizard by selecting the AXIOM Databinding Technology.
Again, I spent the most of the time by Fault implementation:
 
public class AddNumbersImpl {
private static final String SCHEMA_NAMESPACE = "http://duke.example.org/xsd";
private OMFactory omFactory = OMAbstractFactory.getOMFactory();

public OMElement addNumbers(OMElement requestElement) throws XMLStreamException {

int value1 = Integer.valueOf(getRequestParam(requestElement, "arg0")).intValue();
int value2 = Integer.valueOf(getRequestParam(requestElement, "arg1")).intValue();
int result = value1+value2;
if (result < 0) {

OMNode text = omFactory.createOMText("negative result");
OMNode text1 = omFactory.createOMText("the result is negative");

OMNamespace omNs = omFactory.createOMNamespace(SCHEMA_NAMESPACE, "ns");

OMElement responseChildElement = omFactory.createOMElement("faultInfo", omNs);
responseChildElement.addChild(text);
OMElement responseChildElement1 = omFactory.createOMElement("message", omNs);
responseChildElement1.addChild(text1);

OMElement faultElement = omFactory.createOMElement("AddNumbersFault", omNs);
faultElement.addChild(responseChildElement);
faultElement.addChild(responseChildElement1);


SOAPFault fault = OMAbstractFactory.getSOAP11Factory().createSOAPFault();
SOAPFaultCode code = OMAbstractFactory.getSOAP11Factory().createSOAPFaultCode();
code.setText(fault.getNamespace().getPrefix()+":Server");

SOAPFaultReason faultstring = OMAbstractFactory.getSOAP11Factory().createSOAPFaultReason();
faultstring.setText("negative result");

SOAPFaultDetail detail = OMAbstractFactory.getSOAP11Factory().createSOAPFaultDetail();
detail.addChild(faultElement);

fault.setCode(code);
fault.setReason(faultstring);
fault.setDetail(detail);

return fault;

} else {
String resultStr = String.valueOf(result);
OMNode response = omFactory.createOMText(resultStr);
return createResponse("addNumbersResponse", "return", response);
}
}

public void oneWayInt(OMElement requestElement) throws XMLStreamException {
System.out.println("AXIOM:oneWayInt request: "+requestElement);
}

private String getRequestParam(OMElement requestElement, String requestChildName) {
OMElement requestChildElement =
requestElement.getFirstChildWithName(new QName(SCHEMA_NAMESPACE, requestChildName));
return requestChildElement.getText();
}

private OMElement createResponse(String responseElementName, String responseChildName, OMNode response) {
OMNamespace omNs = omFactory.createOMNamespace(SCHEMA_NAMESPACE, "ns");
OMElement responseElement = omFactory.createOMElement(responseElementName, omNs);
OMElement responseChildElement = omFactory.createOMElement(responseChildName, omNs);
responseChildElement.addChild(response);
responseElement.addChild(responseChildElement);
return responseElement;
}
}

Axis with Xmlbeans

This is the WS Stack supporting also by Axis2 technology. The skeleton class can be generated by Axis Service from Wsdl wizard by selecting the Xmlbeans Databinding Technology.
The implementation is quite straightforward similar to Axis2 ADB. The awkwardness of this approach is the number of classes(225) generated by selecting this option. I am not an expert in Xmlbeans so this number may be reduced somehow. This is the implementation class:
public class AddNumbersImpl implements AddNumbersServiceSkeletonInterface {

public AddNumbersResponseDocument addNumbers(org.example.duke.xsd.AddNumbersDocument addNumbers0) throws AddNumbersFault {
//System.out.println("Xmlbeans: addNumbers request: "+addNumbers0);
int result = addNumbers0.getAddNumbers().getArg0() + addNumbers0.getAddNumbers().getArg1();
if (result < 0) {
AddNumbersFault fault = new AddNumbersFault();
AddNumbersFaultDocument faultDoc = AddNumbersFaultDocument.Factory.newInstance();
org.example.duke.xsd.AddNumbersFault fDetail = org.example.duke.xsd.AddNumbersFault.Factory.newInstance();
fDetail.setFaultInfo("negative result "+result);
fDetail.setMessage("the result is negative");
faultDoc.setAddNumbersFault(fDetail);
fault.setFaultMessage(faultDoc);
throw fault;
}
AddNumbersResponseDocument response = AddNumbersResponseDocument.Factory.newInstance();
AddNumbersResponse resp = AddNumbersResponse.Factory.newInstance();
resp.setReturn(result);
response.setAddNumbersResponse(resp);
return response;
}

public void oneWayInt(org.example.duke.xsd.OneWayIntDocument oneWayInt2) {
//TODO implement this method
System.out.println("Xmlbeans: oneWayInt request: "+oneWayInt2);
}

}

Summary

I tried to compare 5 different techniques of 2 popular WS Stacks(JAX-WS and Axis2) to implement a simple SOAP web service. The role of all these techniques is to process the XML payload, of the request, and generate the response. The high level techniques like JAX_WS, Axis with ADB or Axis with Xmlbeans look very similar in their essence and protect users from working with low level XML APIs and from knowing the structure of SOAP messages. Both low level implementation techniques documented here are difficult to use and cumbersome in some extent. On other side these techniques can be used even in cases when high level techiques fail.

Finally I've created a simple JAX-WS client on my local machine for measuring the avarage response time. I used JDK1.5 with Tomcat 6.0 web server.

This is the client code:
    public static void main(String[] args) {

addnumbers3.AddNumbersService3 service = new addnumbers3.AddNumbersService3();
addnumbers3.AddNumbersService3PortType port = service.getAddNumbersService3SOAP11PortHttp();
((BindingProvider) port).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
// this value depends on real location of the service wsdl
"http://localhost:8084/axis2/services/AddNumbersService3?wsdl");

long sum = 0L;
Random random = new Random(System.currentTimeMillis());
for (int i=0;i<10000;i++) {
try { // Call Web Service Operation

int arg0 = random.nextInt(100);
int arg1 = random.nextInt(100);
// TODO process result here
long startTime = System.currentTimeMillis();
int result = port.addNumbers(arg0, arg1);
long endTime = System.currentTimeMillis();
long time = (endTime - startTime);
sum+=time;
} catch (AddNumbersFault_Exception ex) {
System.out.println("fault = "+ex.getFaultInfo().getFaultInfo()+":"+ex.getFaultInfo().getMessage());
}
}
double avrg = sum/10000.0;
System.out.println("Avarage response time = "+avrg);
}
Finally this is the result table considering 3 aspects: Ease of Implementation, Response Time and the Number of Generated Classes:

Technique Ease of Implementation Response Time Generated Classes
JAX-WS (with wsimport) ***** 0.57 ms 9
JAX-WS (Provider API without JAXB) * 1.15 ms 0
JAX-WS (Provider API with JAXB) *** 2.36 ms 6
Axis2 with ADB **** 0.62 ms 14
Axis2 with Xmlbeans **** 0.69 ms 225
AXIOM ** 0.65 ms 0


Note: the response times are relative depending on hardware configuration. The Ease of Use aspect may be considered subjective depending on how much experience you have with particular WS Stack.
Published at DZone with permission of its author, Milan Kuchtiak.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jeff Rubinoff replied on Tue, 2008/04/29 - 9:31am

Good stuff, the most broad overview of SOAP service creation options in NB that I've seen.

Silvano Maffeis replied on Wed, 2008/06/18 - 10:38am

Any reason why you are not using more meaningful parameter names than arg0, arg1 etc.?

I'm having problems deploying a webservice on JBoss. Works fine if parameter names

are arg0, arg1 etc. Gives a WSException during deployment if the parameters are meaningful.

 

silvano

Milan Kuchtiak replied on Thu, 2008/06/19 - 1:20am

arg0, arg1 - parameter names in addNumbers method correspond to SEI class signature that was generated by wsimport utility from wsdl file.

Changing param names in method shouldn't be a problem.

Silvano Maffeis replied on Thu, 2008/06/19 - 2:18am in response to: Milan Kuchtiak

Not a problem, as long as you annotate each parameter in your web service implementation class with @WebParam(name="xyz"), where xyz corresponds to the XSD element name used in the WSDL. (I do this when I use document/literal encoding with wrappers enabled). Without the @WebParam annotations you will get errors like

WSException: arg0 is not a valid property on class

when deploying webservices to JBoss.

Sendal Jepit replied on Sun, 2010/07/18 - 4:34am

Share the Netbeans project please,...

David Memem replied on Thu, 2010/09/02 - 11:01am

Is there a simple way to create a server and client which is purely XML over HTTP using jax/jax-ws.

 I'm trying to write a client to talk to an existing system, which is not over SOAP.  I'm trying Jax for thed first time, but what ever I do it always adds SOAP to the message, envelope etc..

I may have to resort to posting it with URL, but its over SSL through a proxy, so I figured it would be better to use an existing platform/framework.

 

Thanks

Setsuna Seiei replied on Wed, 2011/05/25 - 2:20am

This is really helpful Milan, thanks for this tutorial.

Carla Brian replied on Sat, 2012/04/28 - 10:51pm

One way to create a web service application is to start by coding the endpoint in Java. If you are developing your Java web service from scratch this is the most direct approach. - Naperville Dentists

Erin Jacksen replied on Mon, 2012/04/30 - 4:30am

This is an awesome tutorial on Java web services and I appreciate it for showing to us fiber to the home construction

Caesar Montero replied on Tue, 2012/05/01 - 5:08pm

I’m familiar with the frameworks that you’ve suggested but need to brush up on them so that I can implement your methods more efficiently grand rapids photo booth

Md Homayun Rashed replied on Tue, 2012/05/22 - 8:35pm

wow good post.Now i am very pleased to read this article.Now new post are available her"FIRSTAID":http://www.privatecpr.com

Bhaskar Karambelkar replied on Fri, 2012/05/25 - 10:35am

For JAX-WS (Provider API with JAXB), you don't need to instantiate the JAXBContext for every invocation of the WS.

Jaxb Context creation is a costly affair and JAXBContext is thread safe (although the marshaller/unmarsheller are not ), and usually  done in a static block / init method.

 If you move the jaxb context creation line. i.e.

JAXBContext jc = JAXBContext.newInstance( "org.example.duke.xsd" );

 out of the API call, and make "jc" static, I think you'll see better performance numbers for that use case.

 Also I would be interested in performance numbers with CXF + its various data bindings.

Steve Sdas replied on Tue, 2012/09/25 - 9:01am

To go on I had to modify the wsdl file a little: AddNumbers.wsdl (the schema namespace is changed).Las Vegas

Jason Bourne replied on Fri, 2012/10/19 - 3:10am

Too much useful elements are distributed here,I really valued type above details ,In previous I was looking like that,now I found all the details which I want,So thanks for giving decent publish. Share It

Steve Sdas replied on Mon, 2012/11/12 - 12:59pm

I have been intelligent for hours and I haven't gone through such awesome stuff. http://waterbayec.org

Steve Sdas replied on Tue, 2012/11/20 - 12:46pm

Your articles and listing are inspirational. marble polishing

Jason Bourne replied on Fri, 2012/12/14 - 1:45am in response to: Silvano Maffeis

 

This is my first opportunity to visit this website. I found some interesting things and I will apply to the development of my blog. Thanks for sharing useful information.
gymastic rings

Bryan Low replied on Tue, 2012/12/18 - 7:30am

Woodlands EC  is a 99-years leasehold property development located at Woodlands Produce 16 in Position 25. With expected success in mid 2016, it contains 14 techniques with 653 designs and seems to be 20 storeys high. It is a brief generate away from Woodlands and Admiralty MRT Position. Future people will be able simply strolling to the nearby Windows windows windows windows vista Factor or a brief generate to Causeway Factor for some near near close relatives fun and actions. A truly unique way of way of lifestyle is awaiting you.

Matt Coleman replied on Wed, 2012/12/19 - 12:42am

great techniques for WSDL...anymore techniques..buffalo ny SEO  could really use this

Bryan Low replied on Mon, 2012/12/24 - 10:45pm

Tanah Merah New Launch is also near top level educational institutions such as Anglican High University, St. Anthony’s Canossian Primary& Extra University and Temasek Younger Higher education. Tampines Younger Higher education, Temasek Polytechnic and World Higher education (East Campus) is also around in the place.

For vehicle business owners, it needs less than 25 minutes to generate to the business hub and amazing Orchard Road purchasing area, via Pan-Island Expressway (PIE) and Southern southern Shore Expressway (ECP).A amazing and exclusive way of way of way of life is looking forward to you.Please see urban vista venture details and floor programs for more details.

Bryan Low replied on Tue, 2013/01/08 - 10:17am

Stratum Condo will be available via Pasir Ris MRT position. Traveling to Changi Terminal as well as the Expo position is therefore very practical. It is also near to many cafes along the Loyang position.

Bryan Low replied on Fri, 2013/01/18 - 1:22am

Sant Ritz is a new and upcoming condominium located in the Potong Pasir area, within a short drive to Little India, Orchard and city area. With expected completion in mid 2016, it comprises of 3 towers with 214 units and stands 12 storeys tall. Future residents will be able to walk to the existing Potong Pasir MRT. With such a short drive to the city area as well as the orchard and bugis area, entertainment for your love ones will come at a stone’s throw away.

Bryan Low replied on Fri, 2013/02/01 - 9:59pm

Several buses are available near Twin Fountains EC along with shopping centers and restaurants. Twin Fountains EC is also near Causeway Point as well as Woodlands Waterfront. Entertainment for your loved ones and friends are therefore at your fingertips with the full condo facilities as well as the amenities near Twin Fountains EC.

Twin Fountains

Mark Lewis replied on Mon, 2013/02/04 - 1:10pm

Wonderful information, although there seem to be a lot of spam comments on this page -- was this intentional? Tight Line Productions 

San Patrick replied on Tue, 2013/02/05 - 5:25am

 Thanks for sharing such a nice list of techniques, tricks, tips and ideas for developing java web services from WSDL. This is what I am looking for. I really appreciate your effort and work that you have done for us.

Hotel Contact number 

San Patrick

Bryan Low replied on Sun, 2013/02/24 - 4:45am

Bartley Ridge facilities provide full family entertainment needs for your family and loved ones. Indulge in a serene and tranquil lifestyle right in the heart of Bartley.

Bartley Ridge

Andy Man replied on Fri, 2013/03/01 - 7:08am

Jurong Gateway Condo's location  is in the middle of 5 shopping malls, is something that is not seen in other areas of Singapore, except Orchard Road. It is a great project, likewise the Ang Mo Kio Cluster.
 

Eric Lim replied on Wed, 2013/03/06 - 8:09am

Great info on WSDL. Thanks for sharing. 

New Launch | Urban Vista 


Bryan Low replied on Thu, 2013/03/07 - 10:11pm

Hillview Peak is also near elite schools such as CHIJ Our Lady Queen Of Peace and Assumption English School & Assumption Pathway School. Bukit Panjang Primary School and Chestnut Drive Secondary School are also around in the area.For vehicle owners, it takes less than 25 minutes to drive to the business hub and vibrant Orchard Road shopping district, via Bukit Timah Expressway (BKE) and Ayer Rajah Expressway (AYE).A wonderful and unique lifestyle awaits you. Please see Hillview Peak project datails and units available for more information.

Hillview Condo

Andy Man replied on Mon, 2013/03/25 - 10:36am

 Belgravia Villas  is well located in the heart of Singapore, just a mere 20 minutes drive from the Central Business District via the CTE. It is located along Ang Mo Kio Avenue 5, in District 20. Ang Mo Kio is a matured estate with great transport infrastructure, including MRT, and many buses linking this estate with others.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.