Service Builder

Service Builder String column length in Liferay

Service Builder generated entity String columns have a standard length of 75 characters. Here’s a tutorial on how to change the Service Builder String column length.
If you are looking at the most obvious place like service.xml file then you are wrong. You have to look into portlet-model-hints.xml file.
Now this file is updated when you run service builder, but it will keep your modifications to column entries.


<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "">

<service-builder package-path="com.example" auto-namespace-tables="false">
	<entity name="Entity" local-service="true" human-name="Entity" table="my_entity" remote-service="true">

		<column name="entityId" type="long" primary="true" />

		<column name="groupId" type="long" />
		<column name="companyId" type="long" />
		<column name="userId" type="long" />
		<column name="userName" type="String" />
		<column name="createDate" type="Date" />
		<column name="modifiedDate" type="Date" />

		<column name="veryLongField" type="String"></column>
		<column name="approvalDate" type="Date"></column>
		<column name="comments" type="String"></column>



Now assuming we have an Entity with fields like veryLongField and comments and approvalDate we can modify the auto-generated portlet-model-hints.xml file to look something like this:

<?xml version="1.0"?>
	<hint-collection name="TEXTAREA">
		<hint name="display-height">100</hint>
		<hint name="display-width">500</hint>
		<hint name="max-length">32768</hint>
	<hint-collection name="DATEFIELD">
		<hint name="month-nullable">true</hint>
		<hint name="day-nullable">true</hint>
		<hint name="year-nullable">true</hint>
		<hint name="show-time">false</hint>
	<model name="com.example.Entity">
		<field name="entityId" type="long" />
		<field name="groupId" type="long" />
		<field name="companyId" type="long" />
		<field name="userId" type="long" />
		<field name="userName" type="String" />
		<field name="createDate" type="Date" />
		<field name="modifiedDate" type="Date" />
		<field name="veryLongField" type="String">
			<hint name="max-length">255</hint>
		<field name="approvalDate" type="Date">
			<hint-collection name="DATEFIELD" />
			<hint name="year-range-delta">90</hint>
			<hint name="year-range-future">true</hint>
		<field name="comments" type="String">
			<hint-collection name="TEXTAREA" />

Notice how we are defining a hint for max-legth so that the database column would also be 255 characters.
We are also defining a hint-collection to re-use the same hints multiple times.
Once we have run service builder again, the corresponding SQL table files and entity classes are updated to reflect our changes.
In case you are wondering, yes there are few more hints that you can use.

Model Hint Values and Descriptions

Name Value Type Description Default
auto-escape boolean sets whether text values should be escaped via HtmlUtil.escape true
autoSize boolean displays the field in a for scrollable text area false
day-nullable boolean allows the day to be null in a date field false
default-value String sets the default value for a field (empty String)
display-height integer sets the display height of the form field rendered using the aui taglib 15
display-width integer sets the display width of the form field rendered using the aui taglib 350
editor boolean sets whether to provide an editor for the input false
max-length integer sets the maximum column size for SQL file generation 75
month-nullable boolean allows the month to be null in a date field false
secret boolean sets whether hide the characters input by the user false
show-time boolean sets whether to show include time along with the date true
upper-case boolean converts all characters to upper case false
year-nullable boolean allows the year to be null in a date field false
year-range-delta integer specifies the number of years to display from today’s date in a date field rendered with the aui taglib 5
year-range-future boolean sets whether to include future dates true
year-range-past boolean sets whether to include past dates true
Here be dragons
default-day-delta integer ??? ???
default-month-delta integer ??? ???
default-year-delta integer ??? ???
check-tab boolean ??? ???

For the full list of Model Hints for Liferay 6.2 you can take a look at this page in the developer guide:

As you can see it’s actually rather simple to modify Service Builder String column length.

If you have a question or having trouble getting this thing working then feel free to write me a comment and I’ll do my best to help you out. If you would like to read more about Liferay related subjects then also make sure to comment on that and if you liked what you read then make sure to subscribe – It’s FREE!

AUI Autocomplete with service builder json datasource

Since it’s not so trivial to correctly understand AlloyUI Autocomplete that’s shipped with Liferay 6.2 then here’s an example on how to make an autocomplete that uses a custom service builder json web service as a datasource.
We will use AUI Autocomplete widget and then user Liferay Service library to fetch the result from our own custom service builder built JSON web service.

This is the look we are trying to achive:
aui autocomplete service builder

Full portlet view.jsp code:

<%@ taglib uri="" prefix="portlet" %>
<%@ taglib uri="" prefix="liferay-theme" %>
<%@ taglib uri="" prefix="liferay-ui"%>
<%@ taglib uri="" prefix="aui" %>

<liferay-theme:defineObjects />

<aui:input name="contactName" type="text" />

<aui:script use="autocomplete-list,aui-base,aui-io-request-deprecated,autocomplete-filters,autocomplete-highlighters,datasource,datasource-get,datatable-datasource">

// Please note that this contact portlet service is a service builder generated JSON web service.
// We pass the groupId as a query param because our service expects it. Liferay has a nice javascript method for finding the group id.
var contactSearchDS = new A.DataSource.IO({source: '/api/jsonws/'+Liferay.ThemeDisplay.getScopeGroupId()});

var contactSearchQueryTemplate = function(query) {
        // Here's an example on how to pass additional parameters to the query for you service
        // In our case we are fetching only the first 20 items and specify the ordering by name
	var output = '&name='+query.trim()+'&sort=name&dir=asc&start=0&end=20';
	return output;

var contactSearchLocator = function (response) {
	var responseData = A.JSON.parse(response[0].responseText);
// For debugging you can do: console.debug(responseData);
    return responseData;

var contactSearchFormatter = function (query, results) {
	return, function (result) {
// For debugging: console.debug(result.raw);
		return '<strong>'+result.raw.fullName+'</strong><br/>'' '' ';

var contactSearchTextLocator = function (result) {
// This is what we place in the input once the user selects an item from the autocomplete list.
// In our case we want to put contact full name in there.
	return result.row.fullName;

var contactSearchInput = new A.AutoCompleteList({
	allowBrowserAutocomplete: 'false',
	resultHighlighter: 'phraseMatch',
	activateFirstItem: 'false',
	inputNode: '#<portlet:namespace/>contactName',
	render: 'true',
	source: contactSearchDS,
	requestTemplate: contactSearchQueryTemplate,
	resultListLocator: contactSearchLocator,
        resultFormatter: contactSearchFormatter,
	resultTextLocator: contactSearchTextLocator		


We’ll post an example of “multi-autocomplete” input also soon. That one requires a lot more code but allows selecting multiple contacts and shows them as “tags” above the input box. Much like the facebook name finder works.

As always, if you have questions or suggestions then please comment below.