Skip to content

Commit e0f181e

Browse files
authored
Merge pull request #52 from yangziwen/master
added ObjectToJsonSerializer
2 parents 0e93e2a + e3bc3f7 commit e0f181e

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-0
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@
131131
<artifactId>reactor-core</artifactId>
132132
<version>1.1.6.RELEASE</version>
133133
</dependency>
134+
<dependency>
135+
<groupId>com.alibaba</groupId>
136+
<artifactId>fastjson</artifactId>
137+
<version>1.2.24</version>
138+
</dependency>
134139

135140
<!-- Do not change below dependency version unless testing properly -->
136141
<dependency>
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* Copyright (c) 2014-2015 Janith Bandara, This source is a part of
3+
* Audit4j - An open source auditing framework.
4+
* http://audit4j.org
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.audit4j.core;
20+
21+
import java.lang.reflect.Field;
22+
import java.lang.reflect.Modifier;
23+
import java.util.Collections;
24+
import java.util.HashMap;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.concurrent.ConcurrentHashMap;
28+
import java.util.concurrent.ConcurrentMap;
29+
30+
import org.audit4j.core.annotation.DeIdentify;
31+
import org.audit4j.core.annotation.DeIdentifyUtil;
32+
import org.audit4j.core.annotation.IgnoreAudit;
33+
34+
import com.alibaba.fastjson.JSON;
35+
import com.alibaba.fastjson.serializer.PropertyFilter;
36+
import com.alibaba.fastjson.serializer.ValueFilter;
37+
38+
/**
39+
* The Class ObjectToJsonSerializer.
40+
*
41+
* @author Ziwen Yang
42+
*/
43+
public final class ObjectToJsonSerializer implements ObjectSerializer {
44+
45+
/* (non-Javadoc)
46+
* @see org.audit4j.core.ObjectSerializer#serialize(java.util.List, java.lang.Object, java.lang.String, org.audit4j.core.annotation.DeIdentify)
47+
*/
48+
@Override
49+
public void serialize(List<org.audit4j.core.dto.Field> auditFields, Object object,
50+
String objectName, DeIdentify deidentify) {
51+
String name = '"' + objectName + '"';
52+
String json = toJson(object, deidentify);
53+
auditFields.add(new org.audit4j.core.dto.Field(name, json, object.getClass().getName()));
54+
}
55+
56+
/**
57+
* Converts an object to json.
58+
*
59+
* @param object an object
60+
* @param deidentify the deidentify
61+
* @return a json string of the object
62+
*/
63+
public final static String toJson(Object object, DeIdentify deidentify) {
64+
if (isPrimitive(object)) {
65+
Object deidentifiedObj = deidentifyObject(object, deidentify);
66+
String primitiveValue = String.valueOf(deidentifiedObj);
67+
if (object instanceof String || object instanceof Character || !object.equals(deidentifiedObj)) {
68+
primitiveValue = '"' + primitiveValue + '"';
69+
}
70+
return primitiveValue;
71+
}
72+
return JSON.toJSONString(object, JsonFilter.INSTANCE);
73+
}
74+
75+
/**
76+
* Checks if is primitive.
77+
*
78+
* @param object the object
79+
* @return true, if is primitive
80+
*/
81+
public final static boolean isPrimitive(Object object) {
82+
if (object instanceof String || object instanceof Number || object instanceof Boolean
83+
|| object instanceof Character) {
84+
return true;
85+
}
86+
return false;
87+
}
88+
89+
/**
90+
* Deidentify object
91+
*
92+
* @param object the object to deidentify
93+
* @param deidentify deidentify definition
94+
* @return
95+
*/
96+
public final static Object deidentifyObject(Object object, DeIdentify deidentify) {
97+
if (object == null || deidentify == null) {
98+
return object;
99+
}
100+
return DeIdentifyUtil.deidentify(String.valueOf(object),
101+
deidentify.left(), deidentify.right(),
102+
deidentify.fromLeft(), deidentify.fromRight());
103+
}
104+
105+
106+
/**
107+
* The Class JsonFilter
108+
*
109+
* It helps to mask or exclude object fields which are marked with certain annotations
110+
*/
111+
static class JsonFilter implements PropertyFilter, ValueFilter {
112+
113+
private static final ConcurrentMap<String, Map<String, DeIdentify>> DEIDENTIFY_CACHE =
114+
new ConcurrentHashMap<String, Map<String, DeIdentify>>();
115+
116+
private static final ConcurrentMap<String, Map<String, Boolean>> IGNORE_AUDIT_CACHE =
117+
new ConcurrentHashMap<String, Map<String, Boolean>>();
118+
119+
static final JsonFilter INSTANCE = new JsonFilter();
120+
121+
private JsonFilter() {}
122+
123+
/**
124+
* Value will be processed if there is a DeIdentify annotation on top of the field
125+
*
126+
* @param object an object
127+
* @param name name of the object field
128+
* @param value value of the object field
129+
* @return the processed value of the object field
130+
*/
131+
@Override
132+
public Object process(Object object, String name, Object value) {
133+
Class<?> clazz = object.getClass();
134+
String key = clazz.getName();
135+
Map<String, DeIdentify> deidentifyMap = DEIDENTIFY_CACHE.get(key);
136+
if (deidentifyMap == null) {
137+
DEIDENTIFY_CACHE.putIfAbsent(key, createDeIdentifyMapping(clazz));
138+
deidentifyMap = DEIDENTIFY_CACHE.get(key);
139+
}
140+
return deidentifyObject(value, deidentifyMap.get(name));
141+
}
142+
143+
/**
144+
* Field will be excluded if there is an IgnoreAudit annotation on top of the field
145+
*
146+
* @param object an object
147+
* @param name name of the object field
148+
* @param value value of the object field
149+
* @return true if this field should be serialized, otherwise it will be ignored
150+
*/
151+
@Override
152+
public boolean apply(Object object, String name, Object value) {
153+
Class<?> clazz = object.getClass();
154+
String key = clazz.getName();
155+
Map<String, Boolean> ignoreAuditMap = IGNORE_AUDIT_CACHE.get(key);
156+
if (ignoreAuditMap == null) {
157+
IGNORE_AUDIT_CACHE.putIfAbsent(key, createIgnoreAuditMapping(clazz));
158+
ignoreAuditMap = IGNORE_AUDIT_CACHE.get(key);
159+
}
160+
return !Boolean.TRUE.equals(ignoreAuditMap.get(name));
161+
}
162+
163+
private static Map<String, DeIdentify> createDeIdentifyMapping(Class<?> clazz) {
164+
Map<String, DeIdentify> mapping = new HashMap<String, DeIdentify>();
165+
for (Field field : clazz.getDeclaredFields()) {
166+
if (Modifier.isStatic(field.getModifiers())) {
167+
continue;
168+
}
169+
if (field.isAnnotationPresent(DeIdentify.class)) {
170+
mapping.put(field.getName(), field.getAnnotation(DeIdentify.class));
171+
}
172+
}
173+
if (mapping.isEmpty()) {
174+
mapping = Collections.emptyMap();
175+
}
176+
return mapping;
177+
}
178+
179+
private static Map<String, Boolean> createIgnoreAuditMapping(Class<?> clazz) {
180+
Map<String, Boolean> mapping = new HashMap<String, Boolean>();
181+
for (Field field : clazz.getDeclaredFields()) {
182+
if (Modifier.isStatic(field.getModifiers())) {
183+
continue;
184+
}
185+
if (!field.isAnnotationPresent(IgnoreAudit.class)) {
186+
continue;
187+
}
188+
mapping.put(field.getName(), Boolean.TRUE);
189+
}
190+
if (mapping.isEmpty()) {
191+
mapping = Collections.emptyMap();
192+
}
193+
return mapping;
194+
}
195+
196+
}
197+
198+
}

0 commit comments

Comments
 (0)