/**
* diqube: Distributed Query Base.
*
* Copyright (C) 2015 Bastian Gloeckle
*
* This file is part of diqube.
*
* diqube is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diqube.util;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
/**
* Utility which can set all properties to <code>null</code> on an object.
*
* @author Bastian Gloeckle
*/
public class NullUtil {
private static final Set<Class<?>> PRIMITIVE_TYPES = new HashSet<>(Arrays.asList(Long.TYPE, Integer.TYPE, Byte.TYPE,
Short.TYPE, Float.TYPE, Double.TYPE, Character.TYPE, Boolean.TYPE));
/**
* Set all properties to <code>null</code> on the given object, enabling the GC to clean up some objects.
*
* @param o
* The object to <code>null</code> the properties of
* @param exceptionHandler
* Called when an excpetion occurs. If <code>null</code> exceptions will be swallowed. Consumes the fieldName
* and the exception that happened.
*/
public static void setAllPropertiesToNull(Object o, BiConsumer<String, Exception> exceptionHandler) {
List<Field> allFields = new ArrayList<>();
Deque<Class<?>> allClasses = new LinkedList<>();
allClasses.add(o.getClass());
while (!allClasses.isEmpty()) {
Class<?> curClass = allClasses.pop();
if (curClass.equals(Object.class))
continue;
for (Field declaredField : curClass.getDeclaredFields()) {
if (Modifier.isFinal(declaredField.getModifiers()) || Modifier.isStatic(declaredField.getModifiers()))
continue;
if (!PRIMITIVE_TYPES.contains(declaredField.getType()))
allFields.add(declaredField);
}
allClasses.add(curClass.getSuperclass());
}
for (Field fieldToNull : allFields) {
makeAccessible(fieldToNull);
try {
fieldToNull.set(o, null);
} catch (IllegalArgumentException | IllegalAccessException e) {
if (exceptionHandler != null)
exceptionHandler.accept(fieldToNull.getName(), e);
}
}
}
private static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}
}