Fórum

Service Builder - Return complex type

Andy S, modificado 11 Anos atrás.

Service Builder - Return complex type

New Member Postagens: 8 Data de Entrada: 08/09/10 Postagens Recentes
Hi,

Hope you can help me. I'm using LR 6.1 EE to build a web service. The service.xml contains an empty entity tag because I want to modify the implementation class to access an external system. My web service will be accessed remotely via SOAP.

<!--?xml version="1.0" encoding="UTF-8"?-->

<service-builder package-path="my.package">
	<author>Foo</author>
	<namespace>myspace</namespace>
	<entity name="foo" local-service="true" remote-service="true">
	</entity>
</service-builder>


For example, suppose I want to return the following type:
public class Status {
	int	status;
	String	statusDescription;
}


My question is, what steps do I need to take in order to return my Status type from this web service and be able to access it as a SOAP web service. Is this possible ?

Thanks for any help you can give me with this, this is my first Liferay project and I'm a bit stuck.
thumbnail
Pavel Savinov, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

Junior Member Postagens: 94 Data de Entrada: 24/09/12 Postagens Recentes
Hi Andy!

You should create an entity with 2 columns - status and statusDescription and a finder which returns an entity, like this:
<entity name="Status" local-service="true" remote-service="true" human-name="Status">
  <column name="statusId" type="int" />
  <column name="statusDescription" type="String" />
  <!-- other columns -->

  <finder name="StatusId" return-type="Status">
     <finder-column name="statusDescription" /> 
  </finder>
</entity>
<!-- other entities -->

such code will generate a service(remote(which could be accessible via SOAP) and local. Then you have to implement your finder method in *ServiceImpl class and rebuild the service builder to add your finder to *ServiceUtil class.

You can read more about Service Builder in the development guide:
http://www.liferay.com/documentation/liferay-portal/6.1/development/-/ai/service-build-5
http://www.liferay.com/documentation/liferay-portal/6.1/development/-/ai/soap-web-services
Andy S, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

New Member Postagens: 8 Data de Entrada: 08/09/10 Postagens Recentes
Hi Pavel,

Thanks for getting back to me so quickly!
You should create an entity with 2 columns ...

I guess this will create a table in the Liferay database. If so can I delete it after modifying the implementation class and would there be anything else to clear up?
thumbnail
Pavel Savinov, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

Junior Member Postagens: 94 Data de Entrada: 24/09/12 Postagens Recentes
Sure, you can specify not to use the data-source in the entity's definition.
Check out last post in that thread:
http://www.liferay.com/community/forums/-/message_boards/message/16407861
Andy S, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

New Member Postagens: 8 Data de Entrada: 08/09/10 Postagens Recentes
Hi Pavel,
I've tried using an entity similar to the one you showed me and I need a bit more advice if possible. Here is what I did:-
1. Used this entity and ran build-service:-
<entity name="Status" local-service="true" remote-service="true">
	<column name="statusId" type="int" primary="true" />
	<column name="statusDescription" type="String" />
	<finder name="StatusId" return-type="Status">
		<finder-column name="statusId" />
	</finder>
</entity>


2. Added import statement to StatusServiceImpl.java
import *package*.service.base.StatusServiceBaseImpl;


3. The problem comes when I try to add the finder method to the StatusServiceImpl.java
public Status findByStatusId(){
	   ...?
	}


My question is; how do I instantiate a Status object and populate it's properties (statusId and statusDescription) before returning it?
thumbnail
Pavel Savinov, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

Junior Member Postagens: 94 Data de Entrada: 24/09/12 Postagens Recentes
In fact, it's just your own decision, for example, you can create in directly, like this:

in your StatusServiceImpl.java:

public Status findByStatusId(long statusId) {
   Status status = new StatusImpl();
   /* StatusImpl was generated by ServiceBuilder  */
   status.setStatusId(statusId);
   status.setDescription("Only one status for any ID!");
   return status;
}

and than re-run ServiceBuilder, or create some helper class which will generate your Status object depending on the passed statusId.
I'm not sure that it's the most elegant solution of the problem, but it'll work.
Andy S, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

New Member Postagens: 8 Data de Entrada: 08/09/10 Postagens Recentes
Thanks Pavel,

I tried that and the service builds.
Andy S, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

New Member Postagens: 8 Data de Entrada: 08/09/10 Postagens Recentes
Hi Pavel,

Thanks for your help so far, I really appreciate it!

I've mainly got this working now, but there is still an issue I need advice for. In order to get the service builder to build the service I had to include a primaryKey="true" attribute in the Status entity
<entity name="Status" local-service="true" remote-service="true">
	<column name="statusId" type="int" primary="true" />
	<column name="statusDescription" type="String" />
	<finder name="StatusId" return-type="Status">
		<finder-column name="statusId" />
	</finder>
</entity>


Here is the test method that returns some dummy values
public Status getStatus (){
		Status status = new StatusImpl();
		status.setStatusDescription("status description");
		status.setStatusId(0);
		return status;
	}


Here is the response from the SOAP service when called
<!--?xml version="1.0" encoding="utf-8"?-->
<soapenv:envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<soapenv:body>
		<ns1:getstatusresponse soapenv:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:http.service.mynamespace">
			<getstatusreturn href="#id0" />
		</ns1:getstatusresponse>
		<multiref id="id0" soapenc:root="0" soapenv:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:StatusSoap" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="http://model.mynamespace">
			<primarykey href="#id1" />
			<statusdescription xsi:type="soapenc:string">status description</statusdescription>
			<statusid href="#id2" />
		</multiref>
		<multiref id="id2" soapenc:root="0" soapenv:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">0</multiref>
		<multiref id="id1" soapenc:root="0" soapenv:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">0</multiref>
	</soapenv:body>
</soapenv:envelope>


The addition of the primary key in the entity is causing the service to generate the multiref elements and appears to substitute my dummy value for statusId into it, complicating the output.

If I try removing the primaryKey="true" attribute, then I get the following exception when running build-service
freemarker.template.TemplateModelException: Method public boolean com.liferay.portal.tools.servicebuilder.Entity.isHierarchicalTree() threw an exception when invoked on com.liferay.portal.tools.servicebuilder.Entity@9432bc12
...
Caused by: java.lang.RuntimeException: There is no primary key for entity Status
...

This is why I added the primary key attribute.

Do you any way around this?

Is there a way of getting the service to build without using the primary key route I took ?
thumbnail
Pavel Savinov, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

Junior Member Postagens: 94 Data de Entrada: 24/09/12 Postagens Recentes
Hmm...
I've taken a look at the ServiceBuilder's source...unfortunatelly, it's necesary to create at least one column, marked as a primary key.
You can create some utility column, which will act like a PK, but use only statusId and statusDescription.
Andy S, modificado 11 Anos atrás.

RE: Service Builder - Return complex type

New Member Postagens: 8 Data de Entrada: 08/09/10 Postagens Recentes
Thanks Pavel,

I tried that and added a pk column to the Status entity and set attribute primary="true" and removed the primary attribute from the statusId element. This now returns even more multiRef elements. Here's an extract from the WSDL
...
<complextype name="StatusSoap">
	<sequence>
		<element name="pk" type="xsd:int" />
		<element name="primaryKey" type="xsd:int" />
		<element name="statusDescription" nillable="true" type="soapenc:string" />
		<element name="statusId" type="xsd:int" />
	</sequence>
</complextype>
...

I think its determined to have primary key fields in the SOAP response. Perhaps this just isn't possible to achieve. Would you agree?

There is one other approach that's been suggested to me, which is to modify the Apache Axis 1.4 WSDD file by adding a beanMapping element. As described here: https://ws.apache.org/axis/java/user-guide.html#EncodingYourBeansTheBeanSerializer. From your understanding of Service Builder. Do you think its worth trying this ?