Skip to content

Commit

Permalink
Fixes #18, Fixes #19
Browse files Browse the repository at this point in the history
Added Support for class level annotation
Removed restriction to be used only on JDK1.7 and above.
Compiled with JDK-6
Refactored package name
  • Loading branch information
VenomVendor committed Aug 1, 2018
1 parent 52c73d4 commit 20f741c
Show file tree
Hide file tree
Showing 14 changed files with 81 additions and 65 deletions.
3 changes: 1 addition & 2 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ plugins:
- "java-basic"
- "java-braces"
- "java-codesize"
- "java-codesize"
- "java-design"
- "java-naming"
sonar-java:
enabled: true
config:
tests_patterns:
- src/test/**
sonar.java.source: 8
sonar.java.source: 1.6
11 changes: 0 additions & 11 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
# Team Yaml
coverage:
round: down
precision: 5

# Repository Yaml
coverage:
round: up
range: 0..10

# Used in Codecov after updating
coverage:
round: up
range: 0..10
precision: 5

codecov:
branch: master
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
> Removes invalid objects during Gson parsing which are marked as required, yet null/empty.
[![Build Status](https://img.shields.io/travis/VenomVendor/NullDefense/master.svg?logo=travis)](https://travis-ci.org/VenomVendor/NullDefense)
[![Apache License v2.0](https://img.shields.io/badge/License-Apache%202.0-brightgreen.svg)](https://github.com/VenomVendor/NullDefense/blob/master/LICENSE)
[![Latest Version](https://img.shields.io/maven-metadata/v/https/jcenter.bintray.com/com/venomvendor/gson-nulldefense/maven-metadata.xml.svg)](https://bintray.com/bintray/jcenter/NullDefense)
[![Apache License v2.0](https://img.shields.io/badge/license-Apache--2.0-brightgreen.svg)](https://github.com/VenomVendor/NullDefense/blob/master/LICENSE)
[![Latest Version](https://img.shields.io/maven-metadata/v/https/jcenter.bintray.com/com/venomvendor/gson-nulldefense/maven-metadata.xml.svg)](https://bintray.com/venomvendor/maven/NullDefense/_latestVersion)

# Code Quality
[![Codecov](https://codecov.io/gh/VenomVendor/NullDefense/branch/master/graph/badge.svg)](https://codecov.io/gh/VenomVendor/NullDefense)
Expand Down
10 changes: 10 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ New Line is created by adding TWO whitespace at EOL

# Release Notes

## [v2.0.0](https://github.com/VenomVendor/NullDefense/releases/tag/v2.0.0)
**Date**: 02-Aug-2018
**Fixes**: [#18](https://github.com/VenomVendor/NullDefense/issues/18),
[#19](https://github.com/VenomVendor/NullDefense/issues/19)
**Notes**
- Breaking Changes
- Renamed package
- Added support for class level annotation
- Removed Restriction to use JDK 1.7+

## [v1.0.1](https://github.com/VenomVendor/NullDefense/releases/tag/v1.0.1)
**Date**: 27-Jul-2018
**Fixes**: [#16](https://github.com/VenomVendor/NullDefense/issues/16)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.venomvendor.library.gson;
package com.venomvendor.gson;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
Expand All @@ -30,16 +30,15 @@
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;


/**
* Adapter for removing <b>null</b> objects &amp; <b>empty</b> Collection once the object is created.
* Adapter for removing <b>null</b> objects &amp; <b>empty</b> CollectionS, once object is created.
* <p>
* Incase of {@link Collection}, empty collection is invalid unless {@link #retainEmptyCollection()}
* is called explicility to retain empty collection. This can be useful incase of search results.
* is called explicitly to retain empty collection. This can be useful incase of search results.
* <p>
* This also processess all collection &amp; finally removes {@code null} from Collection,
* This also processes all collection &amp; finally removes {@code null} from Collection,
* further processes collection to remove all {@code null} from results.<pre>
* public class Parent {
* &#064;Mandatory
Expand Down Expand Up @@ -76,7 +75,7 @@
* .create();
* </pre>
*/
@SuppressWarnings("All")
@SuppressWarnings("WeakerAccess")
public final class NullDefenseTypeAdapterFactory implements TypeAdapterFactory {

/* Annotation by which variables are marked mandatory */
Expand All @@ -98,7 +97,9 @@ public final class NullDefenseTypeAdapterFactory implements TypeAdapterFactory {
* @throws NullPointerException if annotated class is null
*/
public NullDefenseTypeAdapterFactory(Class<? extends Annotation> annotatedType) {
Objects.requireNonNull(annotatedType, "Annotation class cannot be null");
if (annotatedType == null) {
throw new NullPointerException("Annotation class cannot be null");
}
this.annotatedType = annotatedType;
removeEmptyCollection();
}
Expand All @@ -124,15 +125,18 @@ public NullDefenseTypeAdapterFactory retainEmptyCollection() {
return this;
}

/**
* {@inheritDoc}
*/
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
TypeAdapter<T> author = gson.getDelegateAdapter(this, type);
return new DefensiveAdapter<>(author, discardEmpty, annotatedType);
return new DefensiveAdapter<T>(author, discardEmpty, annotatedType);
}

/**
* Adapter that removes null objects.
* A callback is recieved from Gson to read &amp; write.
* A callback is received from Gson to read &amp; write.
* During {@link #read(JsonReader)} if return value is null, then this is ignored.
*
* @param <T> Type of object.
Expand All @@ -149,8 +153,6 @@ private static final class DefensiveAdapter<T> extends TypeAdapter<T> {

DefensiveAdapter(TypeAdapter<T> author, boolean discardEmpty,
Class<? extends Annotation> annotatedType) {
Objects.requireNonNull(author, "TypeAdapter cannot be null");
Objects.requireNonNull(annotatedType, "Annotation cannot be null");
this.author = author;
this.discardEmpty = discardEmpty;
this.annotatedType = annotatedType;
Expand All @@ -163,11 +165,12 @@ public void write(JsonWriter out, T value) throws IOException {

@Override
public T read(JsonReader reader) throws IOException {
// Usually never null
// Usually non-null
if (reader == null) {
return null;
}
// Get read value, after processing with gson
// This is where Object is created from json
T result = author.read(reader);

// if null, return it.
Expand All @@ -186,12 +189,18 @@ public T read(JsonReader reader) throws IOException {
* @return same result if not null or conditional empty, else {@code null}
*/
private T getFilteredData(T result) {
for (Field field : result.getClass().getDeclaredFields()) {
Class<?> clz = result.getClass();
boolean isMarkedInClz = clz.isAnnotationPresent(annotatedType);

for (Field field : clz.getDeclaredFields()) {
if (field.getType().isPrimitive()) {
// Skip primitives
continue;
}
if (containsInvalidData(result, field)) {

boolean isMarked = isMarkedInClz || field.isAnnotationPresent(annotatedType);
if (containsInvalidData(result, field, isMarked)) {
// Discard result & return null.
return null;
}
}
Expand All @@ -203,21 +212,21 @@ private T getFilteredData(T result) {
/**
* Check if data contains null or empty objects only on annotated fields
*
* @param result data to process
* @param field declared variable in current object
* @param result data to process
* @param field declared variable in current object
* @param isMarked represents if current field is annotated
* @return {@code true} if data is invalid
*/
private boolean containsInvalidData(T result, Field field) {
private boolean containsInvalidData(T result, Field field, boolean isMarked) {
// Check if current field is marked
if (field.isAnnotationPresent(annotatedType)) {
if (isMarked) {
// To read private fields
field.setAccessible(true);

if (hasInvalidData(result, field)) {
return true;
}
// Validate data
return hasInvalidData(result, field);
}
// Data is valid
// Consider data as valid
return false;
}

Expand All @@ -234,10 +243,11 @@ private boolean hasInvalidData(T result, Field field) {
// Lil, costly operation.
value = field.get(result);
} catch (IllegalAccessException ex) {
// Can't help
ex.printStackTrace();
}

// Check of emptyness
// Check for emptiness
return isEmpty(value);
}

Expand All @@ -258,14 +268,14 @@ private boolean isEmpty(Object value) {
* @param value data to process
* @return {@code true} if data is invalid
*/
@SuppressWarnings("SuspiciousMethodCalls")
private boolean isEmptyCollection(Object value) {
if (value instanceof Collection) {
Collection subCollection = ((Collection) value);
Collection<?> subCollection = ((Collection) value);
// Cost is O(N^2), due to rearrangement
subCollection.removeAll(NULL_COLLECTION);
if (discardEmpty && subCollection.isEmpty()) {
return true;
}
// Remove object if collection is empty.
return discardEmpty && subCollection.isEmpty();
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
* limitations under the License.
*/

package com.venomvendor.library.gson;
package com.venomvendor.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapterFactory;
import com.venomvendor.library.gson.annotation.MandatoryTest;
import com.venomvendor.library.gson.util.ResourceHelperTest;
import com.venomvendor.gson.annotation.MandatoryTest;
import com.venomvendor.gson.util.ResourceHelperTest;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
* limitations under the License.
*/

package com.venomvendor.library.gson;
package com.venomvendor.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.venomvendor.library.gson.annotation.MandatoryTest;
import com.venomvendor.library.gson.model.ChildTest;
import com.venomvendor.library.gson.model.ParentTest;
import com.venomvendor.gson.annotation.MandatoryTest;
import com.venomvendor.gson.model.ChildTest;
import com.venomvendor.gson.model.ParentTest;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
* limitations under the License.
*/

package com.venomvendor.library.gson.annotation;
package com.venomvendor.gson.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface MandatoryTest {

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@
* limitations under the License.
*/

package com.venomvendor.library.gson.model;
package com.venomvendor.gson.model;

import com.venomvendor.library.gson.annotation.MandatoryTest;

import com.venomvendor.gson.annotation.MandatoryTest;

@MandatoryTest
public class ChildTest {

@MandatoryTest
private String name;
private boolean isMale;
@MandatoryTest
private int age;
@MandatoryTest
private LanguageTest language;

public String getName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* limitations under the License.
*/

package com.venomvendor.library.gson.model;
package com.venomvendor.gson.model;

import com.venomvendor.library.gson.annotation.MandatoryTest;
import com.venomvendor.gson.annotation.MandatoryTest;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -25,6 +25,7 @@ public class LanguageTest {

@MandatoryTest
private List<String> knownLanguages = new ArrayList<>();
private List<String> learning;

public List<String> getKnownLanguages() {
return knownLanguages;
Expand All @@ -33,4 +34,12 @@ public List<String> getKnownLanguages() {
public void setKnownLanguages(List<String> knownLanguages) {
this.knownLanguages = knownLanguages;
}

public List<String> getLearning() {
return learning;
}

public void setLearning(List<String> learning) {
this.learning = learning;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
* limitations under the License.
*/

package com.venomvendor.library.gson.model;
package com.venomvendor.gson.model;

import com.google.gson.annotations.SerializedName;
import com.venomvendor.library.gson.annotation.MandatoryTest;
import com.venomvendor.library.gson.util.CustomListTest;
import com.venomvendor.gson.annotation.MandatoryTest;
import com.venomvendor.gson.util.CustomListTest;

public class ParentTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.venomvendor.library.gson.util;
package com.venomvendor.gson.util;

import java.util.ArrayList;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.venomvendor.library.gson.util;
package com.venomvendor.gson.util;

import java.io.File;
import java.io.IOException;
Expand Down
4 changes: 2 additions & 2 deletions version.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extra["major"] = 1
extra["major"] = 2
extra["minor"] = 0
extra["patch"] = 1
extra["patch"] = 0

val suffix = ""
val version = "${extra["major"]}.${extra["minor"]}.${extra["patch"]}"
Expand Down

0 comments on commit 20f741c

Please sign in to comment.