Squiggly
The Squiggly Filter is a Jackson JSON PropertyFilter, which selects properties of an object/list/map using a subset of the Facebook Graph API filtering syntax.
Install / Use
/learn @bohnman/SquigglyREADME
THIS PROJECT IS NO LONGER MAINTAINED
Apologies to everyone. I just don't have any time to maintain this. Feel free to fork or let me know if you're interested in taking this over.
Important Note
As of version 1.3.2, the preferred way to specify nested filters is to use square brackets intead of braces.
Preferred: assignee[firstName]
No longer Preferred but will still work: assignee{firstName}
The reason for this is that newer versions of Tomcat no longer allow braces to be specified on the url without being escaped. Square brackets are still permitted in the url and it is preferred to make the syntax url friendly.
Squiggly Filter For Jackson
Contents
- What is it?
- Prerequisites
- Installation
- General Usage
- Reference Object
- Top-Level Filters
- Nested Filters
- Dot Syntax
- Regex Filters
- Other Filters
- Resolving Conflicts
- Excluding Fields
- Property Views
- More Examples
- Custom Integration
- Changing the Defaults
- Metrics
- Limitations
<a name="what-is-it"></a>What is it?
The Squiggly Filter is a Jackson JSON PropertyFilter, which selects properties of an object/list/map using a subset of the Facebook Graph API filtering syntax.
Probably the most common use of this library is to filter fields on the querystring like so:
?fields=id,reporter[firstName]
Integrating Squiggly into your webapp is covered in Custom Integration.
<a name="prerequisites"></a>Requirements
- Java 7+
- ANTLR
- Commons Lang 3
- Google Guava
- Jackson JSON (version 2.6+)
<a name="installation"></a>Installation
Maven
<dependency>
<groupId>com.github.bohnman</groupId>
<artifactId>squiggly-filter-jackson</artifactId>
<version>1.3.18</version>
</dependency>
<a name="general-usage"></a>General Usage
ObjectMapper objectMapper = Squiggly.init(new ObjectMapper(), "assignee{firstName}");
Issue object = new Issue(); // replace this with your object/collection/map here
System.out.println(SquigglyUtils.stringify(objectMapper, object));
Alternatively, if you need more control over configuring the ObjectMapper, you can do it this way:
String filterId = SquigglyPropertyFilter.FILTER_ID;
SquigglyPropertyFilter propertyFilter = new SquigglyPropertyFilter("assignee[firstName]"); // replace with your filter here
SimpleFilterProvider filterProvider = new SimpleFilterProvider().addFilter(filterId, propertyFilter);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setFilterProvider(filterProvider);
objectMapper.addMixIn(Object.class, SquigglyPropertyFilterMixin.class);
Issue object = new Issue(); // replace this with your object/collection/map here
System.out.println(SquigglyUtils.stringify(objectMapper, object));
Also, you can generate a Plain Old Java Object (POJO) instead of a JSON String
ObjectMapper objectMapper = Squiggly.init(new ObjectMapper(), "assignee{firstName}");
System.out.println(SquigglyUtils.objectify(objectMapper, object, Object.class));
For applying filter on Collection of Objects and for returning Collection of POJOs instead of JSON String
List<User> users = Arrays.asList(
new User("Peter", 12, "Dinklage"),
new User("Lena", 13, "Heady"));
String filter = "firstName,age";
ObjectMapper objectMapper = Squiggly.init(new ObjectMapper(), filter);
List<User> filteredUsers = SquigglyUtils.listify(objectMapper, users, User.class);
// setify is also availble
<a name="reference-object"></a>Reference Object
For the filtering examples, let's use an the example object of type Issue
{
"id": "ISSUE-1",
"issueSummary": "Dragons Need Fed",
"issueDetails": "I need my dragons fed pronto.",
"reporter": {
"firstName": "Daenerys",
"lastName": "Targaryen"
},
"assignee": {
"firstName": "Jorah",
"lastName": "Mormont"
},
"actions": [
{
"id": null,
"type": "COMMENT",
"text": "I'm going to let Daario get this one.",
"user": {
"firstName": "Jorah",
"lastName": "Mormont"
}
},
{
"id": null,
"type": "CLOSE",
"text": "All set.",
"user": {
"firstName": "Daario",
"lastName": "Naharis"
}
}
],
"properties": {
"priority": "1",
"email": "motherofdragons@got.com"
}
}
<a name="top-level-filters"></a>Top-Level Filters
Select No Fields
String filter = "";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {}
Select Single Field
filter = "id";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"id":"ISSUE-1"}
Select Multiple Fields
filter = "id,issueSummary"
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"id":"ISSUE-1", "issueSummary":"Dragons Need Fed"}
Select Fields Using Wildcards
filter = "issue*";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"issueSummary":"Dragons Need Fed", "issueDetails": "I need my dragons fed pronto."}
Select All Fields
filter = "**";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints the same json as our example object
Select All Fields of object, but only base fields of associated objects (more on this later)
filter = "*";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
/* prints the following:
{
"id": "ISSUE-1",
"issueSummary": "Dragons Need Fed",
"issueDetails": "I need my dragons fed pronto.",
"reporter": {
"firstName": "Daenerys",
"lastName": "Targaryen"
},
"assignee": {
"firstName": "Jorah",
"lastName": "Mormont"
},
"actions": [
{
"id": null,
"type": "COMMENT",
"text": "I'm going to let Daario get this one.."
},
{
"id": null,
"type": "CLOSE",
"text": "All set."
}
],
"properties": {
"priority": "1",
"email": "motherofdragons@got.com"
}
}
*/
<a name="nested-filters"></a>Nested Filters
Select Single Nested Field
String filter = "assignee[firstName]";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"assignee":{"firstName":"Jorah"}}
Select Multiple Nested Fields
String filter = "actions[text,type]";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"actions":[{"type":"COMMENT","text":"I'm going to let Daario get this one.."},{"type":"CLOSE","text":"All set."}]}
// NOTE: use can also use wildcards (e.g. actions{t*})
Select Same Field From Different Nested Objects
String filter = "(assignee,reporter)[firstName]";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"reporter":{"firstName":"Daenerys"},"assignee":{"firstName":"Jorah"}}
Select Deeply Nested Field
String filter = "actions[user[lastName]]";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"actions":[{"user":{"lastName":"Mormont"}},{"user":{"lastName":"Naharis"}}]}
<a name="dot-syntax"></a>Dot Syntax
As an alternative to using the braces syntax for nested filter, you can use the dot syntax
String filter = "assignee.firstName";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"assignee":{"firstName":"Jorah"}}
You can exclude fields using the dot syntax. Note that the exclusion applies to the last field.
String filter = "-assignee.firstName";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"assignee":{"lastName":"Mormont"}}
You can also combine the dot syntax with the nested syntax.
String filter = "actions.user[firstName]";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"actions":[{"user":{"firstName":"Jorah"}},{"user":{"firstName":"Daario"}}]}
One limitation is that you cannot use the | syntax with the dot syntax
String filter = "(actions.user,assignee)[firstName]";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// throws exception
<a name="regex-filters"></a>Regex Filters
In addition to using wildcards, you can also use regular expressions.
Here's an example:
String filter = "~iss[a-z]e.*~";
ObjectMapper mapper = Squiggly.init(mapper, filter);
System.out.println(SquigglyUtils.stringify(mapper, issue));
// prints {"issueSummary":"Dragons Need Fed","issueDetails":"I need my dragons fed pronto."}
Notice the tildes mark the begin and of the regex pattern.
You can also specifiy a case insensitive match.
String filter = "~iss[a-z]esumm.*~i";
ObjectMa
Related Skills
node-connect
347.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
