THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Browse Source

First working version

tags/release/16.01
Thibault Meyer 3 years ago
parent
commit
fa1c8f22c9
14 changed files with 1524 additions and 4 deletions
  1. +13
    -4
      .gitignore
  2. +12
    -0
      .travis.yml
  3. +21
    -0
      LICENSE
  4. +104
    -0
      README.md
  5. +11
    -0
      checkstyle-suppressions.xml
  6. +91
    -0
      checkstyle.xml
  7. +183
    -0
      pom.xml
  8. +353
    -0
      src/main/java/com/zero_x_baadf00d/partialize/Partialize.java
  9. +50
    -0
      src/main/java/com/zero_x_baadf00d/partialize/annotation/PartialField.java
  10. +56
    -0
      src/main/java/com/zero_x_baadf00d/partialize/annotation/PartialFields.java
  11. +57
    -0
      src/main/java/com/zero_x_baadf00d/partialize/converter/Converter.java
  12. +48
    -0
      src/main/java/com/zero_x_baadf00d/partialize/converter/DefaultConverter.java
  13. +276
    -0
      src/test/java/BasicTest.java
  14. +249
    -0
      src/test/java/StandardTest.java

+ 13
- 4
.gitignore View File

@@ -1,12 +1,21 @@
*.class
*.java~


# IntelliJ IDEA
.idea/
*.iml

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear
target/


# Properties files
*.properties
!src/main/resources/version.properties


# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

+ 12
- 0
.travis.yml View File

@@ -0,0 +1,12 @@
language: java

jdk:
- oraclejdk8

install:
- mvn clean
- mvn checkstyle:check
- mvn compile

script:
- mvn package

+ 21
- 0
LICENSE View File

@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016 Thibault Meyer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 104
- 0
README.md View File

@@ -0,0 +1,104 @@
# Partialize


[![Latest release](https://img.shields.io/badge/latest_release-16.01-orange.svg)](https://github.com/0xbaadf00d/partialize/releases)
[![Build](https://img.shields.io/travis-ci/0xbaadf00d/partialize.svg?branch=master&style=flat)](https://travis-ci.org/0xbaadf00d/partialize)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/0xbaadf00d/partialize/master/LICENSE)

Partialize is a Java based library helping you to implement the JSON partial responses on your project.
*****



## Questions and issues
The GitHub issue tracker is only for bug reports and feature requests. Anything
else, such as questions for help in using the library, should be posted in
[StackOverflow](http://stackoverflow.com/questions/tagged/partialize?sort=active)
under tags `partialize` and `java`.




## Build the library
To compile Partialize, you must ensure that Java 8 and Maven are correctly
installed.

#> mvn compile
#> mvn package




## Usage


### Objects to render as JSON

```java
@PartialFields(
allowedFields = {"uid", "firstName", "lastName", "emails", "createDate"},
wildcardFields = {"uid", "firstName", "lastName"}
)
public class AccountModel {
private UUID uid;
private String firstName;
private String lastName;
private String password;
private List<AccountEmailModel> emails;
@PartialField("example.converts.JodaDateTimeConverter")
private DateTime createDate;

/* ADD GETTER / SETTER METHODS HERE */
}
```

```java
@PartialFields(
allowedFields = {"uid", "emails", "isDefault"},
wildcardFields = {"emails", "isDefault"}
)
public class AccountEmailModel {
private UUID uid;
private String email;
private Boolean isDefault;

/* ADD GETTER / SETTER METHODS HERE */
}
```


### Code
```java
final AccountModel account = AccountModel.find().where().eq("id", 1).findUnique();

final String fields = "firstName,lastName,emails(email,isDefault),createDate";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, AccountModel.class, account);
System.out.println(result);
```


### Output
```json
{
"firstName": "John",
"lastName": "Smith",
"emails": [
{
"email": "john.smith@domain.local",
"isDefault": true
},
{
"email": "john@domain.local",
"isDefault": false
}
],
"createDate": "2016-01-15T23:45:12"
}
```




## License
This project is released under terms of the [MIT license](https://raw.githubusercontent.com/0xbaadf00d/partialize/master/LICENSE).

+ 11
- 0
checkstyle-suppressions.xml View File

@@ -0,0 +1,11 @@
<?xml version="1.0"?>

<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.0//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_0.dtd">

<suppressions>
<suppress checks="FinalParameters"
files="Partialize.java"
lines="281"/>
</suppressions>

+ 91
- 0
checkstyle.xml View File

@@ -0,0 +1,91 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<module name="Checker">
<module name="NewlineAtEndOfFile"/>
<module name="FileLength"/>
<module name="FileTabCharacter"/>
<module name="RegexpSingleline">
<property name="format" value="\s+$"/>
<property name="message" value="Line has trailing spaces."/>
</module>
<module name="RegexpMultiline">
<property name="format" value="\r?\n[\t ]*\r?\n[\t ]*\r?\n"/>
<property name="message" value="Unnecessary consecutive lines"/>
</module>
<module name="RegexpSingleline">
<property name="format" value="/\*\* +\p{javaLowerCase}"/>
<property name="fileExtensions" value="java"/>
<property name="message" value="First sentence in a comment should start with a capital letter"/>
</module>
<module name="RegexpMultiline">
<property name="format" value="/\*\*\W+\* +\p{javaLowerCase}"/>
<property name="fileExtensions" value="java"/>
<property name="message" value="First sentence in a comment should start with a capital letter"/>
</module>
<module name="TreeWalker">
<module name="ConstantName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="MethodLength"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<module name="IllegalImport"/>
<module name="UnusedImports">
<property name="processJavadoc" value="true"/>
</module>
<module name="LineLength">
<property name="max" value="180"/>
</module>
<module name="GenericWhitespace"/>
<module name="EmptyForIteratorPad"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter">
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS"/>
</module>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="OneTopLevelClass"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<module name="LeftCurly"/>
<module name="RightCurly"/>
<module name="CovariantEquals"/>
<module name="EmptyStatement"/>
<module name="EqualsAvoidNull"/>
<module name="EqualsHashCode"/>
<module name="IllegalInstantiation"/>
<module name="MissingSwitchDefault"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="InterfaceIsType"/>
<module name="FinalClass"/>
<module name="ArrayTypeStyle"/>
<module name="UpperEll"/>
<module name="FinalParameters"/>
<module name="ArrayTrailingComma"/>
<module name="DeclarationOrder"/>
<module name="DefaultComesLast"/>
<module name="ExplicitInitialization"/>
<module name="FallThrough"/>
<module name="FinalLocalVariable"/>
<module name="HiddenField">
<property name="ignoreConstructorParameter" value="true"/>
<property name="ignoreSetter" value="true"/>
<property name="setterCanReturnItsClass" value="true"/>
</module>
<module name="IllegalCatch"/>
<module name="IllegalThrows"/>
<module name="IllegalToken"/>
<module name="IllegalTokenText"/>
<module name="IllegalType"/>
<module name="InnerAssignment"/>
</module>
</module>

+ 183
- 0
pom.xml View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.zero_x_baadf00d</groupId>
<artifactId>partialize</artifactId>
<version>16.01</version>
<packaging>jar</packaging>
<name>Partialize</name>
<description>JSON partial responses for Java</description>
<url>https://github.com/0xbaadf00d/partialize</url>

<scm>
<connection>scm:git:https://github.com/0xbaadf00d/partialize.git</connection>
<developerConnection>scm:git:https://github.com/0xbaadf00d/partialize.git</developerConnection>
<url>https://github.com/0xbaadf00d/partialize.git</url>
</scm>

<issueManagement>
<url>https://github.com/0xbaadf00d/partialize/issues</url>
<system>GitHub Issues</system>
</issueManagement>

<licenses>
<license>
<name>The MIT License (MIT)</name>
<url>https://raw.githubusercontent.com/0xbaadf00d/partialize/master/LICENSE</url>
</license>
</licenses>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:sszzz</maven.build.timestamp.format>
</properties>

<build>
<plugins>
<!-- Java version to use -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Copy dependencies -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.2</version>
<configuration>
<encoding>UTF-8</encoding>
<show>package</show>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Attach sources -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Sign with GPG -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<configuration>
<keyname>0xBAADF00D</keyname>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Check style -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.17</version>
<configuration>
<configLocation>checkstyle.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<suppressionsLocation>checkstyle-suppressions.xml</suppressionsLocation>
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
<linkXRef>false</linkXRef>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<filtering>false</filtering>
<directory>src/test/resources</directory>
</testResource>
</testResources>
</build>

<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 353
- 0
src/main/java/com/zero_x_baadf00d/partialize/Partialize.java View File

@@ -0,0 +1,353 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Thibault Meyer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.zero_x_baadf00d.partialize;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ContainerNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zero_x_baadf00d.partialize.annotation.PartialField;
import com.zero_x_baadf00d.partialize.annotation.PartialFields;
import com.zero_x_baadf00d.partialize.converter.Converter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
* Create a partial JSON document from any kind of objects.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
public class Partialize {

/**
* Default maximum reachable depth level.
*
* @since 16.01
*/
public static final int DEFAULT_MAXIMUM_DEPTH = 64;

/**
* Default scanner delimiter pattern.
*
* @since 16.01
*/
private static final String SCANNER_DELIMITER = ",";

/**
* Pattern used to extract arguments.
*
* @since 16.01
*/
private final Pattern fieldArgsPattern = Pattern.compile("([a-zA-Z0-9]{1,})\\((.+)\\)");

/**
* Object mapper used to create new object nodes.
*
* @since 16.01
*/
private final ObjectMapper objectMapper;

/**
* The maximum reachable depth level.
*
* @since 16.01
*/
private final int maximumDepth;

/**
* Build a default instance.
*
* @since 16.01
*/
public Partialize() {
this(Partialize.DEFAULT_MAXIMUM_DEPTH);
}

/**
* Build an instance with a specific maximum depth value set.
*
* @param maximumDepth Maximum allowed depth value to set
* @since 16.01
*/
public Partialize(final int maximumDepth) {
this.objectMapper = new ObjectMapper();
this.maximumDepth = maximumDepth > 0 ? maximumDepth : 1;
}

/**
* Build a JSON object from data taken from the scanner and
* the given class type and instance.
*
* @param fields The field query to request
* @param clazz The class of the object to render
* @param instance The instance of the object to render
* @return An instance of {@code ContainerNode}
* @see ContainerNode
* @since 16.01
*/
public ContainerNode buildPartialObject(final String fields, final Class<?> clazz, final Object instance) {
if (instance instanceof Collection<?>) {
final ArrayNode partialArray = this.objectMapper.createArrayNode();
if (((Collection<?>) instance).size() > 0) {
for (final Object o : (Collection<?>) instance) {
partialArray.add(this.buildPartialObject(0, fields, o.getClass(), o));
}
}
return partialArray;
} else {
return this.buildPartialObject(0, fields, clazz, instance);
}
}

/**
* Add requested item on the partial JSON document.
*
* @param depth Current depth level
* @param field The field name
* @param args The field Arguments
* @param partialArray The current partial JSON document part
* @param clazz The class of the object to add
* @param object The object to add
* @since 16.01
*/
private void internalBuild(final int depth, final String field, final String args, final ArrayNode partialArray, final Class<?> clazz, final Object object) {
if (object == null) {
partialArray.addNull();
} else if (object instanceof String) {
partialArray.add((String) object);
} else if (object instanceof Integer) {
partialArray.add((Integer) object);
} else if (object instanceof Long) {
partialArray.add((Long) object);
} else if (object instanceof Double) {
partialArray.add((Double) object);
} else if (object instanceof UUID) {
partialArray.add(object.toString());
} else if (object instanceof Boolean) {
partialArray.add((Boolean) object);
} else if (object instanceof Collection<?>) {
final ArrayNode anotherPartialArray = partialArray.addArray();
if (((Collection<?>) object).size() > 0) {
for (final Object o : (Collection<?>) object) {
this.internalBuild(depth, field, args, anotherPartialArray, o.getClass(), o);
}
}
} else if (object instanceof Enum) {
final String tmp = object.toString();
try {
partialArray.add(Integer.valueOf(tmp));
} catch (NumberFormatException ignore) {
partialArray.add(tmp);
}
} else {
try {
if (clazz.getDeclaredField(field).isAnnotationPresent(PartialField.class)) {
final Class<?> convertClazz = clazz.getDeclaredField(field).getAnnotation(PartialField.class).value();
try {
final Converter converter = (Converter) convertClazz.newInstance();
converter.convert(field, object, partialArray);
} catch (InstantiationException ex) {
ex.printStackTrace();
partialArray.add(object.toString());
}
} else {
partialArray.add(this.buildPartialObject(depth + 1, args, object.getClass(), object));
}
} catch (NoSuchFieldException | IllegalAccessException ignore) {
partialArray.add(this.buildPartialObject(depth + 1, args, object.getClass(), object));
}
}
}

/**
* Add requested item on the partial JSON document.
*
* @param depth Current depth level
* @param field The field name
* @param args The field Arguments
* @param partialObject The current partial JSON document part
* @param clazz The class of the object to add
* @param object The object to add
* @since 16.01
*/
private void internalBuild(final int depth, final String field, final String args, final ObjectNode partialObject, final Class<?> clazz, final Object object) {
if (object == null) {
partialObject.putNull(field);
} else if (object instanceof String) {
partialObject.put(field, (String) object);
} else if (object instanceof Integer) {
partialObject.put(field, (Integer) object);
} else if (object instanceof Long) {
partialObject.put(field, (Long) object);
} else if (object instanceof Double) {
partialObject.put(field, (Double) object);
} else if (object instanceof UUID) {
partialObject.put(field, object.toString());
} else if (object instanceof Boolean) {
partialObject.put(field, (Boolean) object);
} else if (object instanceof Collection<?>) {
final ArrayNode partialArray = partialObject.putArray(field);
if (((Collection<?>) object).size() > 0) {
for (final Object o : (Collection<?>) object) {
this.internalBuild(depth, field, args, partialArray, o.getClass(), o);
}
}
} else if (object instanceof Map<?, ?>) {
this.buildPartialObject(depth + 1, args, object.getClass(), object, partialObject.putObject(field));
} else if (object instanceof Enum) {
final String tmp = object.toString();
try {
partialObject.put(field, Integer.valueOf(tmp));
} catch (NumberFormatException ignore) {
partialObject.put(field, tmp);
}
} else {
try {
if (clazz.getDeclaredField(field).isAnnotationPresent(PartialField.class)) {
final Class<?> convertClazz = clazz.getDeclaredField(field).getAnnotation(PartialField.class).value();
try {
final Converter converter = (Converter) convertClazz.newInstance();
converter.convert(field, object, partialObject);
} catch (InstantiationException ex) {
ex.printStackTrace();
partialObject.put(field, object.toString());
}
} else {
this.buildPartialObject(depth + 1, args, object.getClass(), object, partialObject.putObject(field));
}
} catch (NoSuchFieldException | IllegalAccessException ignore) {
this.buildPartialObject(depth + 1, args, object.getClass(), object, partialObject.putObject(field));
}
}
}

/**
* Build a JSON object from data taken from the scanner and
* the given class type and instance.
*
* @param depth The current depth
* @param fields The field names to requests
* @param clazz The class of the object to render
* @param instance The instance of the object to render
* @return A JSON Object
* @since 16.01
*/
private ObjectNode buildPartialObject(final int depth, final String fields, final Class<?> clazz, final Object instance) {
return this.buildPartialObject(depth, fields, clazz, instance, this.objectMapper.createObjectNode());
}

/**
* Build a JSON object from data taken from the scanner and
* the given class type and instance.
*
* @param depth The current depth
* @param fields The field names to requests
* @param clazz The class of the object to render
* @param instance The instance of the object to render
* @param partialObject The partial JSON document
* @return A JSON Object
* @since 16.01
*/
private ObjectNode buildPartialObject(final int depth, String fields, final Class<?> clazz, final Object instance, final ObjectNode partialObject) {
if (depth <= this.maximumDepth) {
if (clazz.isAnnotationPresent(PartialFields.class)) {
List<String> allowedFields = Arrays.asList(instance.getClass().getAnnotation(PartialFields.class).allowedFields());
List<String> wildCardFields = Arrays.asList(instance.getClass().getAnnotation(PartialFields.class).wildcardFields());
if (allowedFields.isEmpty()) {
allowedFields = new ArrayList<>();
for (final Method m : clazz.getDeclaredMethods()) {
final String methodName = m.getName();
if (methodName.startsWith("get")) {
final char[] c = methodName.substring(3).toCharArray();
c[0] = Character.toLowerCase(c[0]);
allowedFields.add(new String(c));
}
}
}
if (wildCardFields.isEmpty()) {
wildCardFields = allowedFields;
}
if (fields == null || fields.length() == 0) {
fields = wildCardFields.stream().collect(Collectors.joining(","));
}

Scanner scanner = new Scanner(fields);
scanner.useDelimiter(Partialize.SCANNER_DELIMITER);
while (scanner.hasNext()) {
String word = scanner.next();
String args = null;
if (word.compareTo("*") == 0) {
scanner.close();
scanner = new Scanner(wildCardFields.stream().collect(Collectors.joining(",")));
scanner.useDelimiter(Partialize.SCANNER_DELIMITER);
}
if (word.contains("(")) {
while (scanner.hasNext() && (StringUtils.countMatches(word, "(") != StringUtils.countMatches(word, ")"))) {
word += "," + scanner.next();
}
final Matcher m = this.fieldArgsPattern.matcher(word);
if (m.find()) {
word = m.group(1);
args = m.group(2);
}
}
final String field = word;
if (allowedFields.stream().anyMatch(f -> f.toLowerCase(Locale.ENGLISH).compareTo(field.toLowerCase(Locale.ENGLISH)) == 0)) {
try {
final Method method = clazz.getMethod("get" + WordUtils.capitalize(field));
final Object object = method.invoke(instance);
this.internalBuild(depth, field, args, partialObject, clazz, object);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ignore) {
}
}
}
return partialObject;
} else if (instance instanceof Map<?, ?>) {
if (fields == null || fields.isEmpty()) {
for (Map.Entry<?, ?> e : ((Map<?, ?>) instance).entrySet()) {
this.internalBuild(depth, String.valueOf(e.getKey()), null, partialObject, e.getValue() == null ? Object.class : e.getValue().getClass(), e.getValue());
}
} else {
final Map<?, ?> tmpMap = (Map<?, ?>) instance;
for (final String k : fields.split(",")) {
final Object o = tmpMap.get(k);
this.internalBuild(depth, k, null, partialObject, o == null ? Object.class : o.getClass(), o);
}
}
} else {
throw new RuntimeException(clazz.getCanonicalName() + " is not annotated");
}
}
return partialObject;
}
}

+ 50
- 0
src/main/java/com/zero_x_baadf00d/partialize/annotation/PartialField.java View File

@@ -0,0 +1,50 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Thibault Meyer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.zero_x_baadf00d.partialize.annotation;

import com.zero_x_baadf00d.partialize.converter.DefaultConverter;

import java.lang.annotation.*;

/**
* Tell to Partialize the converter to use when all
* built-in converters fails.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PartialField {

/**
* The converted to apply on the field value.
*
* @return The converter class
* @since 16.01
*/
Class<?> value() default DefaultConverter.class;
}

+ 56
- 0
src/main/java/com/zero_x_baadf00d/partialize/annotation/PartialFields.java View File

@@ -0,0 +1,56 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Thibault Meyer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.zero_x_baadf00d.partialize.annotation;

import java.lang.annotation.*;

/**
* Indicate that the decorated class can be processed by Partialize.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PartialFields {

/**
* Allowed field names.
*
* @return An array of allowed field names
* @since 16.01
*/
String[] allowedFields() default {};

/**
* Field names used to replace wildcard. If array is empty, data
* from PartialFields#allowedFields will be used.
*
* @return An array of default field names
* @since 16.01
*/
String[] wildcardFields() default {};
}

+ 57
- 0
src/main/java/com/zero_x_baadf00d/partialize/converter/Converter.java View File

@@ -0,0 +1,57 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Thibault Meyer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.zero_x_baadf00d.partialize.converter;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
* All converters must implement this interface.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
public interface Converter<T> {

/**
* Convert the given data to a JSON compatible format.
*
* @param fieldName The field name
* @param data The data to convert
* @param node The node where to put the converted data
* @since 16.01
*/
void convert(final String fieldName, final T data, final ObjectNode node);

/**
* Convert the given data to a JSON compatible format.
*
* @param fieldName The field name
* @param data The data to convert
* @param node The node where to put the converted data
* @since 16.01
*/
void convert(final String fieldName, final T data, final ArrayNode node);
}

+ 48
- 0
src/main/java/com/zero_x_baadf00d/partialize/converter/DefaultConverter.java View File

@@ -0,0 +1,48 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Thibault Meyer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.zero_x_baadf00d.partialize.converter;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
* Default converter. It simply return the string
* representation of the given object.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
public class DefaultConverter implements Converter<Object> {

@Override
public void convert(final String fieldName, final Object data, final ObjectNode node) {
node.put(fieldName, data.toString());
}

@Override
public void convert(final String fieldName, final Object data, final ArrayNode node) {
node.add(data.toString());
}
}

+ 276
- 0
src/test/java/BasicTest.java View File

@@ -0,0 +1,276 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Thibault Meyer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import com.fasterxml.jackson.databind.node.ContainerNode;
import com.zero_x_baadf00d.partialize.Partialize;
import com.zero_x_baadf00d.partialize.annotation.PartialFields;
import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
* BasicTest.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class BasicTest {

/**
* Handle to the object used on these tests.
*
* @since 16.01
*/
private AccountPojo account;

/**
* Initialize data.
*
* @since 16.01
*/
private void initializePojo() {
if (this.account == null) {
this.account = new AccountPojo();
this.account.setId(1);
this.account.setUid(UUID.randomUUID());
this.account.setFirstName("John");
this.account.setLastName("Smith");

final List<EmailPojo> emails = new ArrayList<>();
this.account.setEmails(emails);

EmailPojo email = new EmailPojo();
email.setId(1);
email.setUid(UUID.randomUUID());
email.setEmail("john.smith@domain.local");
email.setDefault(true);
emails.add(email);

email = new EmailPojo();
email.setId(2);
email.setUid(UUID.randomUUID());
email.setEmail("john@domain.local");
email.setDefault(false);
emails.add(email);
}
}

/**
* @since 16.01
*/
@Test
public void basicTest001() {
this.initializePojo();
final String fields = "firstName,lastName,emails(uid)";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, AccountPojo.class, this.account);

Assert.assertNotNull(result);
Assert.assertEquals("John", result.get("firstName").asText());
Assert.assertEquals("Smith", result.get("lastName").asText());
Assert.assertFalse(result.get("emails").get(0).has("email"));
Assert.assertTrue(result.get("emails").has(1));
Assert.assertFalse(result.get("emails").has(2));
Assert.assertEquals(this.account.getEmails().get(0).getUid().toString(), result.get("emails").get(0).get("uid").asText());
}

/**
* @since 16.01
*/
@Test
public void basicTest002() {
this.initializePojo();
final String fields = "*";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, AccountPojo.class, this.account);

Assert.assertNotNull(result);
Assert.assertTrue(result.has("uid"));
Assert.assertFalse(result.has("id"));
Assert.assertFalse(result.has("emails"));
Assert.assertEquals("John", result.get("firstName").asText());
Assert.assertEquals("Smith", result.get("lastName").asText());
}

/**
* @since 16.01
*/
@Test
public void basicTest003() {
this.initializePojo();
final String fields = "emails(*),firstName";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, AccountPojo.class, this.account);

Assert.assertNotNull(result);
Assert.assertEquals("John", result.get("firstName").asText());
Assert.assertTrue(result.get("emails").has(0));
Assert.assertTrue(result.get("emails").has(1));
Assert.assertFalse(result.get("emails").has(2));
Assert.assertFalse(result.get("emails").get(0).has("email"));
Assert.assertTrue(result.get("emails").get(0).has("uid"));
Assert.assertFalse(result.get("emails").get(0).has("id"));
Assert.assertEquals(this.account.getEmails().get(0).getUid().toString(), result.get("emails").get(0).get("uid").asText());
}

/**
* @since 16.01
*/
@Test
public void basicTest004() {
this.initializePojo();
final String fields = "emails(uid,email),*";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, AccountPojo.class, this.account);

Assert.assertNotNull(result);
Assert.assertEquals("John", result.get("firstName").asText());
Assert.assertEquals("Smith", result.get("lastName").asText());
Assert.assertTrue(result.get("emails").has(0));
Assert.assertTrue(result.get("emails").has(1));
Assert.assertFalse(result.get("emails").has(2));
Assert.assertTrue(result.get("emails").get(0).has("email"));
Assert.assertTrue(result.get("emails").get(0).has("uid"));
Assert.assertFalse(result.get("emails").get(0).has("id"));
Assert.assertEquals(this.account.getEmails().get(0).getUid().toString(), result.get("emails").get(0).get("uid").asText());
}

/**
* EmailPojo.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
@PartialFields(
allowedFields = {"uid", "email", "isDefault"},
wildcardFields = "uid"
)
public static class EmailPojo {

private int id;
private UUID uid;
private String email;
private boolean isDefault;

public int getId() {
return this.id;
}

public void setId(int id) {
this.id = id;
}

public UUID getUid() {
return this.uid;
}

public void setUid(UUID uid) {
this.uid = uid;
}

public String getEmail() {
return this.email;
}

public void setEmail(String email) {
this.email = email;
}

public boolean isDefault() {
return this.isDefault;
}

public void setDefault(boolean aDefault) {
this.isDefault = aDefault;
}
}

/**
* AccountPojo.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
@PartialFields(
allowedFields = {"uid", "firstName", "lastName", "emails"},
wildcardFields = {"uid", "firstName", "lastName"}
)
public static class AccountPojo {

private int id;
private UUID uid;
private String firstName;
private String lastName;
private List<EmailPojo> emails;

public int getId() {
return this.id;
}

public void setId(int id) {
this.id = id;
}

public UUID getUid() {
return this.uid;
}

public void setUid(UUID uid) {
this.uid = uid;
}

public String getFirstName() {
return this.firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return this.lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public List<EmailPojo> getEmails() {
return this.emails;
}

public void setEmails(List<EmailPojo> emails) {
this.emails = emails;
}
}
}

+ 249
- 0
src/test/java/StandardTest.java View File

@@ -0,0 +1,249 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Thibault Meyer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ContainerNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zero_x_baadf00d.partialize.Partialize;
import com.zero_x_baadf00d.partialize.annotation.PartialField;
import com.zero_x_baadf00d.partialize.annotation.PartialFields;
import com.zero_x_baadf00d.partialize.converter.Converter;
import org.joda.time.DateTime;
import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* BasicTest.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class StandardTest {

/**
* Handle to the object used on these tests.
*
* @since 16.01
*/
private BankAccountPojo bankAccount;

/**
* Current datetime.
*
* @since 16.01
*/
private DateTime currentDateTime;

/**
* Initialize data.
*
* @since 16.01
*/
private void initializePojo() {
if (this.bankAccount == null) {
this.currentDateTime = DateTime.now();
this.bankAccount = new BankAccountPojo();
this.bankAccount.setAmount(42.84);
this.bankAccount.setDisplayName("My bank account");
this.bankAccount.setCreateDate(this.currentDateTime);
final List<List<String>> listOfList = new ArrayList<>();
final List<String> item = new ArrayList<>();
item.add("HELLO");
item.add("WORLD");
listOfList.add(item);
listOfList.add(item);
this.bankAccount.setListOfList(listOfList);
final Map<String, Object> attributes = new HashMap<>();
attributes.put("null", null);
attributes.put("integer", 42);
attributes.put("double", 42.84);
attributes.put("boolean", false);
attributes.put("string", "hello world");
this.bankAccount.setAttributes(attributes);
}
}

/**
* @since 16.01
*/
@Test
public void standardTest001() {
this.initializePojo();
final String fields = "displayName,amount,createDate";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, BankAccountPojo.class, this.bankAccount);
Assert.assertNotNull(result);
Assert.assertEquals("My bank account", result.get("displayName").asText());
Assert.assertEquals(42.84, result.get("amount").asDouble(), 0);
Assert.assertNotNull(result.get("createDate"));
Assert.assertEquals(this.currentDateTime.toString("yyyy-MM-dd'T'HH:mm:ss"), result.get("createDate").asText());
}

/**
* @since 16.01
*/
@Test
public void standardTest002() {
this.initializePojo();
final String fields = "displayName,listOfList,createDate";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, BankAccountPojo.class, this.bankAccount);
Assert.assertNotNull(result);
Assert.assertEquals("My bank account", result.get("displayName").asText());
Assert.assertNotNull(result.get("createDate"));
Assert.assertEquals(this.currentDateTime.toString("yyyy-MM-dd'T'HH:mm:ss"), result.get("createDate").asText());
Assert.assertTrue(result.has("listOfList"));
Assert.assertTrue(result.get("listOfList").has(0));
Assert.assertTrue(result.get("listOfList").has(1));
Assert.assertTrue(result.get("listOfList").get(1).has(0));
Assert.assertTrue(result.get("listOfList").get(1).has(1));
Assert.assertEquals("HELLO", result.get("listOfList").get(1).get(0).asText());
Assert.assertEquals("WORLD", result.get("listOfList").get(1).get(1).asText());
}

/**
* @since 16.01
*/
@Test
public void standardTest003() {
this.initializePojo();
final String fields = "attributes";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, BankAccountPojo.class, this.bankAccount);
Assert.assertNotNull(result);
Assert.assertTrue(result.has("attributes"));
Assert.assertTrue(result.get("attributes").has("boolean"));
Assert.assertTrue(result.get("attributes").has("null"));
Assert.assertTrue(result.get("attributes").has("string"));
Assert.assertTrue(result.get("attributes").has("double"));
Assert.assertTrue(result.get("attributes").has("integer"));
}

/**
* @since 16.01
*/
@Test
public void standardTest004() {
this.initializePojo();
final String fields = "attributes(boolean,integer),displayName";
final Partialize partialize = new Partialize();
final ContainerNode result = partialize.buildPartialObject(fields, BankAccountPojo.class, this.bankAccount);
Assert.assertNotNull(result);
Assert.assertTrue(result.has("attributes"));
Assert.assertTrue(result.has("displayName"));
Assert.assertTrue(result.get("attributes").has("boolean"));
Assert.assertTrue(result.get("attributes").has("integer"));
Assert.assertFalse(result.get("attributes").has("null"));
Assert.assertFalse(result.get("attributes").has("string"));
Assert.assertFalse(result.get("attributes").has("double"));
}

/**
* JodaDateTimeConverter.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
public static class JodaDateTimeConverter implements Converter<DateTime> {

@Override
public void convert(String fieldName, DateTime data, ObjectNode node) {
node.put(fieldName, data.toString("yyyy-MM-dd'T'HH:mm:ss"));
}

@Override
public void convert(String fieldName, DateTime data, ArrayNode node) {
node.add(data.toString("yyyy-MM-dd'T'HH:mm:ss"));
}
}

/**
* BankAccountPojo.
*
* @author Thibault Meyer
* @version 16.01
* @since 16.01
*/
@PartialFields
public static class BankAccountPojo {

private String displayName;
private Double amount;
private List<List<String>> listOfList;
private Map<String, Object> attributes;

@PartialField(JodaDateTimeConverter.class)
private DateTime createDate;

public List<List<String>> getListOfList() {
return this.listOfList;
}

public void setListOfList(List<List<String>> listOfList) {
this.listOfList = listOfList;
}

public Map<String, Object> getAttributes() {
return this.attributes;
}

public void setAttributes(Map<String, Object> attributes) {
this.attributes = attributes;
}

public String getDisplayName() {
return this.displayName;
}

public void setDisplayName(String displayName) {
this.displayName = displayName;
}

public Double getAmount() {
return this.amount;
}

public void setAmount(Double amount) {
this.amount = amount;
}

public DateTime getCreateDate() {
return this.createDate;
}

public void setCreateDate(DateTime createDate) {
this.createDate = createDate;
}
}
}

Loading…
Cancel
Save