import swf from XML

This commit is contained in:
2015-01-17 21:35:58 +01:00
parent 7d09f30ae9
commit 1b8eab9414
16 changed files with 421 additions and 15 deletions
@@ -695,7 +695,7 @@ public final class SWF implements SWFContainerItem, Timelined {
frameRate = sis.readUI8("frameRate");
frameCount = sis.readUI16("frameCount");
List<Tag> tags = sis.readTagList(this, 0, parallelRead, true, !checkOnly);
if (tags.get(tags.size() - 1).getId() == EndTag.ID) {
if (tags.size() > 0 && tags.get(tags.size() - 1).getId() == EndTag.ID) {
tags.remove(tags.size() - 1);
} else {
hasEndTag = false;
@@ -2201,6 +2201,8 @@ public final class SWF implements SWFContainerItem, Timelined {
}
public void clearAllCache() {
characters = null;
abcList = null;
clearImageCache();
clearScriptCache();
Cache.clearAll();
@@ -92,10 +92,10 @@ public class SwfXmlExporter {
}
public void exportXml(SWF swf, Document doc, Node node) throws IOException {
generateXml(doc, node, "swf", swf, 0);
generateXml(doc, node, "swf", swf, false, 0);
}
private static void generateXml(Document doc, Node node, String name, Object obj, int level){
private static void generateXml(Document doc, Node node, String name, Object obj, boolean addAsChildNode, int level){
if (obj == null) {
return;
}
@@ -117,7 +117,13 @@ public class SwfXmlExporter {
value = Helper.escapeXML((String) value);
}
((Element) node).setAttribute(name, value.toString());
if (addAsChildNode) {
Element childNode = doc.createElement(name);
childNode.setTextContent(value.toString());
node.appendChild(childNode);
} else {
((Element) node).setAttribute(name, value.toString());
}
} else if (cls.isEnum()) {
((Element) node).setAttribute(name, obj.toString());
} else if (obj instanceof ByteArrayRange) {
@@ -134,7 +140,7 @@ public class SwfXmlExporter {
Element listNode = doc.createElement(name);
node.appendChild(listNode);
for (int i = 0; i < list.size(); i++) {
generateXml(doc, listNode, "item", list.get(i), level + 1);
generateXml(doc, listNode, "item", list.get(i), true, level + 1);
}
} else if (cls.isArray()) {
String arrayType = cls.getComponentType().getSimpleName();
@@ -142,7 +148,7 @@ public class SwfXmlExporter {
node.appendChild(arrayNode);
int length = Array.getLength(obj);
for (int i = 0; i < length; i++) {
generateXml(doc, arrayNode, "item", Array.get(obj, i), level + 1);
generateXml(doc, arrayNode, "item", Array.get(obj, i), true, level + 1);
}
} else {
if (obj instanceof LazyObject) {
@@ -167,7 +173,7 @@ public class SwfXmlExporter {
try {
f.setAccessible(true);
generateXml(doc, objNode, f.getName(), f.get(obj), level + 1);
generateXml(doc, objNode, f.getName(), f.get(obj), false, level + 1);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(SwfXmlExporter.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -0,0 +1,262 @@
/*
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.importers;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
import com.jpexs.decompiler.flash.types.ARGB;
import com.jpexs.decompiler.flash.types.BITMAPDATA;
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD;
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
import com.jpexs.decompiler.flash.types.CLIPEVENTFLAGS;
import com.jpexs.decompiler.flash.types.COLORMAPDATA;
import com.jpexs.decompiler.flash.types.CXFORM;
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.ConstantColorColorTransform;
import com.jpexs.decompiler.flash.types.FILLSTYLE;
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.FOCALGRADIENT;
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
import com.jpexs.decompiler.flash.types.GRADIENT;
import com.jpexs.decompiler.flash.types.GRADRECORD;
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.LINESTYLE;
import com.jpexs.decompiler.flash.types.LINESTYLE2;
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.MORPHFOCALGRADIENT;
import com.jpexs.decompiler.flash.types.MORPHGRADIENT;
import com.jpexs.decompiler.flash.types.MORPHGRADRECORD;
import com.jpexs.decompiler.flash.types.MORPHLINESTYLE;
import com.jpexs.decompiler.flash.types.MORPHLINESTYLE2;
import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.PIX15;
import com.jpexs.decompiler.flash.types.PIX24;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
import com.jpexs.decompiler.flash.types.SOUNDENVELOPE;
import com.jpexs.decompiler.flash.types.SOUNDINFO;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.jpexs.decompiler.flash.types.ZONEDATA;
import com.jpexs.decompiler.flash.types.ZONERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.ReflectionTools;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
*
* @author JPEXS
*/
@SuppressWarnings("unchecked")
public class SwfXmlImporter {
private Map<String, Class> swfTags;
private Map<String, Class> swfObjects;
public void importSwf(SWF swf, String xml) throws IOException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(new InputSource(new StringReader(xml)));
processElement(doc.getDocumentElement(), swf, swf);
} catch (ParserConfigurationException | SAXException ex) {
Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void processElement(Element element, Object obj, SWF swf) {
Class cls = obj.getClass();
for (int i = 0; i < element.getAttributes().getLength(); i++) {
Attr attr = (Attr) element.getAttributes().item(i);
String name = attr.getName();
if (!name.equals("type")) {
try {
Field field = cls.getField(name);
String attrValue = attr.getValue();
field.set(obj, getAs(field.getType(), attrValue));
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
Node childNode = element.getChildNodes().item(i);
if (childNode instanceof Element) {
Element child = (Element) childNode;
String name = child.getTagName();
try {
Field field = cls.getField(name);
Class childCls = field.getType();
if (List.class.isAssignableFrom(childCls)) {
List list = new ArrayList();
for (int j = 0; j < child.getChildNodes().getLength(); j++) {
Node childChildNode = child.getChildNodes().item(j);
if (childChildNode instanceof Element) {
Element childChild = (Element) child.getChildNodes().item(j);
Object childObj = processObject(childChild, ReflectionTools.getFieldSubType(obj, field), swf);
list.add(childObj);
}
}
field.set(obj, list);
} else if (childCls.isArray()) {
List list = new ArrayList();
for (int j = 0; j < child.getChildNodes().getLength(); j++) {
Node childChildNode = child.getChildNodes().item(j);
if (childChildNode instanceof Element) {
Element childChild = (Element) child.getChildNodes().item(j);
Object childObj = processObject(childChild, childCls.getComponentType(), swf);
list.add(childObj);
}
}
Object array = Array.newInstance(childCls.getComponentType(), list.size());
for (int j = 0; j < list.size(); j++) {
Array.set(array, j, list.get(j));
}
field.set(obj, array);
} else {
Object childObj = processObject(child, null, swf);
field.set(obj, childObj);
}
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException ex) {
Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
private Object processObject(Element element, Class requiredType, SWF swf) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException {
String type = element.getAttribute("type");
if (type != null && !type.isEmpty()) {
Object childObj = createObject(type, swf);
processElement(element, childObj, swf);
return childObj;
} else {
return getAs(requiredType, element.getTextContent());
}
}
private Object createObject(String type, SWF swf) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (swfTags == null) {
Map<String, Class> tags = new HashMap<>();
Map<Integer, Class> knownTags = Tag.getKnownClasses();
for (Integer key : knownTags.keySet()) {
Class cls = knownTags.get(key);
tags.put(cls.getSimpleName(), cls);
}
swfTags = tags;
}
Class cls = swfTags.get(type);
if (cls != null) {
return cls.getConstructor(SWF.class).newInstance(swf);
}
if (swfObjects == null) {
Map<String, Class> objects = new HashMap<>();
Class[] knownObjects = new Class[] { ALPHABITMAPDATA.class, ALPHACOLORMAPDATA.class, ARGB.class, BITMAPDATA.class,
BUTTONCONDACTION.class, BUTTONRECORD.class, CLIPACTIONRECORD.class, CLIPACTIONS.class, CLIPEVENTFLAGS.class,
COLORMAPDATA.class, ColorTransform.class, ConstantColorColorTransform.class, CXFORM.class, CXFORMWITHALPHA.class,
FILLSTYLE.class, FILLSTYLEARRAY.class, FOCALGRADIENT.class, GLYPHENTRY.class, GRADIENT.class, GRADRECORD.class,
KERNINGRECORD.class, LANGCODE.class, LINESTYLE.class, LINESTYLE2.class, LINESTYLEARRAY.class, MATRIX.class,
MORPHFILLSTYLE.class, MORPHFILLSTYLEARRAY.class, MORPHFOCALGRADIENT.class, MORPHGRADIENT.class,
MORPHGRADRECORD.class, MORPHLINESTYLE.class, MORPHLINESTYLE2.class, MORPHLINESTYLEARRAY.class, PIX15.class,
PIX24.class, RECT.class, RGB.class, RGBA.class, SHAPE.class, SHAPEWITHSTYLE.class, SOUNDENVELOPE.class,
SOUNDINFO.class, TEXTRECORD.class, ZONEDATA.class, ZONERECORD.class,
CurvedEdgeRecord.class, EndShapeRecord.class, StraightEdgeRecord.class, StyleChangeRecord.class };
for (Class cls2 : knownObjects) {
objects.put(cls2.getSimpleName(), cls2);
}
swfObjects = objects;
}
cls = swfObjects.get(type);
if (cls != null) {
return cls.getConstructor().newInstance();
}
return null;
}
private Object getAs(Class cls, String stringValue) throws IllegalArgumentException, IllegalAccessException {
if (cls == Byte.class || cls == byte.class) {
return Byte.parseByte(stringValue);
} else if (cls == Short.class || cls == short.class) {
return Short.parseShort(stringValue);
} else if (cls == Integer.class || cls == int.class) {
return Integer.parseInt(stringValue);
} else if (cls == Long.class || cls == long.class) {
return Long.parseLong(stringValue);
} else if (cls == Float.class || cls == float.class) {
return Float.parseFloat(stringValue);
} else if (cls == Double.class || cls == double.class) {
return Double.parseDouble(stringValue);
} else if (cls == Boolean.class || cls == boolean.class) {
return Boolean.parseBoolean(stringValue);
} else if (cls == Character.class || cls == char.class) {
return stringValue.charAt(0);
} else if (cls == String.class) {
return stringValue;
} else if (cls == ByteArrayRange.class) {
ByteArrayRange range = new ByteArrayRange(stringValue);
return range;
} else if (cls.isEnum()) {
return Enum.valueOf(cls, stringValue);
} else {
throw new RuntimeException("Unsupported object type.");
}
}
}
@@ -38,8 +38,10 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@@ -134,6 +136,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
private static final Object lockObject = new Object();
private volatile static List<Integer> knownTagIds;
private volatile static Map<Integer, Class> knownTagClasses;
private volatile static List<Integer> requiredTagIds;
public static List<Integer> getKnownTags() {
@@ -227,6 +230,97 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
return knownTagIds;
}
public static Map<Integer, Class> getKnownClasses() {
if (knownTagClasses == null) {
synchronized (lockObject) {
if (knownTagClasses == null) {
Map<Integer, Class> map = new HashMap<>();
map.put(CSMTextSettingsTag.ID, CSMTextSettingsTag.class);
map.put(DebugIDTag.ID, DebugIDTag.class);
map.put(DefineBinaryDataTag.ID, DefineBinaryDataTag.class);
map.put(DefineBitsJPEG2Tag.ID, DefineBitsJPEG2Tag.class);
map.put(DefineBitsJPEG3Tag.ID, DefineBitsJPEG3Tag.class);
map.put(DefineBitsJPEG4Tag.ID, DefineBitsJPEG4Tag.class);
map.put(DefineBitsLossless2Tag.ID, DefineBitsLossless2Tag.class);
map.put(DefineBitsLosslessTag.ID, DefineBitsLosslessTag.class);
map.put(DefineBitsTag.ID, DefineBitsTag.class);
map.put(DefineButton2Tag.ID, DefineButton2Tag.class);
map.put(DefineButtonCxformTag.ID, DefineButtonCxformTag.class);
map.put(DefineButtonSoundTag.ID, DefineButtonSoundTag.class);
map.put(DefineButtonTag.ID, DefineButtonTag.class);
map.put(DefineEditTextTag.ID, DefineEditTextTag.class);
map.put(DefineFont2Tag.ID, DefineFont2Tag.class);
map.put(DefineFont3Tag.ID, DefineFont3Tag.class);
map.put(DefineFont4Tag.ID, DefineFont4Tag.class);
map.put(DefineFontAlignZonesTag.ID, DefineFontAlignZonesTag.class);
map.put(DefineFontInfo2Tag.ID, DefineFontInfo2Tag.class);
map.put(DefineFontInfoTag.ID, DefineFontInfoTag.class);
map.put(DefineFontNameTag.ID, DefineFontNameTag.class);
map.put(DefineFontTag.ID, DefineFontTag.class);
map.put(DefineMorphShape2Tag.ID, DefineMorphShape2Tag.class);
map.put(DefineMorphShapeTag.ID, DefineMorphShapeTag.class);
map.put(DefineScalingGridTag.ID, DefineScalingGridTag.class);
map.put(DefineSceneAndFrameLabelDataTag.ID, DefineSceneAndFrameLabelDataTag.class);
map.put(DefineShape2Tag.ID, DefineShape2Tag.class);
map.put(DefineShape3Tag.ID, DefineShape3Tag.class);
map.put(DefineShape4Tag.ID, DefineShape4Tag.class);
map.put(DefineShapeTag.ID, DefineShapeTag.class);
map.put(DefineSoundTag.ID, DefineSoundTag.class);
map.put(DefineSpriteTag.ID, DefineSpriteTag.class);
map.put(DefineText2Tag.ID, DefineText2Tag.class);
map.put(DefineTextTag.ID, DefineTextTag.class);
map.put(DefineVideoStreamTag.ID, DefineVideoStreamTag.class);
map.put(DoABCDefineTag.ID, DoABCDefineTag.class);
map.put(DoABCTag.ID, DoABCTag.class);
map.put(DoActionTag.ID, DoActionTag.class);
map.put(DoInitActionTag.ID, DoInitActionTag.class);
map.put(EnableDebugger2Tag.ID, EnableDebugger2Tag.class);
map.put(EnableDebuggerTag.ID, EnableDebuggerTag.class);
map.put(EnableTelemetryTag.ID, EnableTelemetryTag.class);
map.put(EndTag.ID, EndTag.class);
map.put(ExportAssetsTag.ID, ExportAssetsTag.class);
map.put(FileAttributesTag.ID, FileAttributesTag.class);
map.put(FrameLabelTag.ID, FrameLabelTag.class);
map.put(ImportAssets2Tag.ID, ImportAssets2Tag.class);
map.put(ImportAssetsTag.ID, ImportAssetsTag.class);
map.put(JPEGTablesTag.ID, JPEGTablesTag.class);
map.put(MetadataTag.ID, MetadataTag.class);
map.put(PlaceObject2Tag.ID, PlaceObject2Tag.class);
map.put(PlaceObject3Tag.ID, PlaceObject3Tag.class);
map.put(PlaceObject4Tag.ID, PlaceObject4Tag.class);
map.put(PlaceObjectTag.ID, PlaceObjectTag.class);
map.put(ProductInfoTag.ID, ProductInfoTag.class);
map.put(ProtectTag.ID, ProtectTag.class);
map.put(RemoveObject2Tag.ID, RemoveObject2Tag.class);
map.put(RemoveObjectTag.ID, RemoveObjectTag.class);
map.put(ScriptLimitsTag.ID, ScriptLimitsTag.class);
map.put(SetBackgroundColorTag.ID, SetBackgroundColorTag.class);
map.put(SetTabIndexTag.ID, SetTabIndexTag.class);
map.put(ShowFrameTag.ID, ShowFrameTag.class);
map.put(SoundStreamBlockTag.ID, SoundStreamBlockTag.class);
map.put(SoundStreamHead2Tag.ID, SoundStreamHead2Tag.class);
map.put(SoundStreamHeadTag.ID, SoundStreamHeadTag.class);
map.put(StartSound2Tag.ID, StartSound2Tag.class);
map.put(StartSoundTag.ID, StartSoundTag.class);
map.put(SymbolClassTag.ID, SymbolClassTag.class);
map.put(VideoFrameTag.ID, VideoFrameTag.class);
map.put(DefineCompactedFont.ID, DefineCompactedFont.class);
map.put(DefineExternalGradient.ID, DefineExternalGradient.class);
map.put(DefineExternalImage.ID, DefineExternalImage.class);
map.put(DefineExternalImage2.ID, DefineExternalImage2.class);
map.put(DefineExternalSound.ID, DefineExternalSound.class);
map.put(DefineExternalStreamSound.ID, DefineExternalStreamSound.class);
map.put(DefineGradientMap.ID, DefineGradientMap.class);
map.put(DefineSubImage.ID, DefineSubImage.class);
map.put(ExporterInfo.ID, ExporterInfo.class);
map.put(FontTextureInfo.ID, FontTextureInfo.class);
knownTagClasses = map;
}
}
}
return knownTagClasses;
}
public static List<Integer> getRequiredTags() {
if (requiredTagIds == null) {
synchronized (lockObject) {
@@ -0,0 +1,303 @@
/*
* Copyright (C) 2010-2015 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.helpers;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class ReflectionTools {
public static Object getValue(Object obj, Field field, int index) throws IllegalArgumentException, IllegalAccessException {
if (getFieldSubSize(obj, field) <= index) {
return null;
}
Object value = field.get(obj);
if (List.class.isAssignableFrom(field.getType())) {
return ((List) value).get(index);
}
if (field.getType().isArray()) {
return Array.get(value, index);
}
return value;
}
public static boolean needsIndex(Field field) {
if (List.class.isAssignableFrom(field.getType())) {
return true;
} else if (field.getType().isArray()) {
return true;
}
return false;
}
@SuppressWarnings("unchecked")
public static int getFieldSubSize(Object obj, Field field) {
Object val;
try {
val = field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException ex) {
return 0;
}
if (List.class.isAssignableFrom(field.getType())) {
return ((List) val).size();
} else if (field.getType().isArray()) {
return Array.getLength(val);
}
return 0;
}
@SuppressWarnings("unchecked")
public static void setValue(Object obj, Field field, int index, Object newValue) throws IllegalArgumentException, IllegalAccessException {
Object value = field.get(obj);
if (needsIndex(field) && index >= getFieldSubSize(obj, field)) { //outofbounds, ignore
return;
}
if (List.class.isAssignableFrom(field.getType())) {
((List) value).set(index, newValue);
} else if (field.getType().isArray()) {
Array.set(value, index, newValue);
} else {
field.set(obj, newValue);
}
}
public static boolean canInstantiate(Class cls) {
if (cls.isInterface()) {
return false;
}
if (Modifier.isAbstract(cls.getModifiers())) {
return false;
}
return true;
}
public static boolean canAddToField(Object object, Field field) {
if (List.class.isAssignableFrom(field.getType())) {
ParameterizedType listType = (ParameterizedType) field.getGenericType();
Class<?> parameterClass = (Class<?>) listType.getActualTypeArguments()[0];
return canInstantiate(parameterClass);
}
if (field.getType().isArray()) {
Object arrValue;
try {
arrValue = field.get(object);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
Class componentClass = arrValue.getClass().getComponentType();
if (componentClass.isPrimitive()) {
return true;
}
return canInstantiate(componentClass);
}
return false;
}
public static Object newInstanceOf(Class cls) throws InstantiationException, IllegalAccessException {
if (cls == Integer.class || cls == int.class) {
return 0;
} else if (cls == Float.class || cls == float.class) {
return 0.0f;
} else if (cls == Double.class || cls == double.class) {
return (double) 0;
} else if (cls == Long.class || cls == long.class) {
return 0L;
}
if (cls.isInterface()) {
return null;
}
if (Modifier.isAbstract(cls.getModifiers())) {
return null;
}
return cls.newInstance();
}
@SuppressWarnings("unchecked")
public static boolean addToList(Object object, Field field, int index) {
if (!List.class.isAssignableFrom(field.getType())) {
return false;
}
List list;
try {
list = (List) field.get(object);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
ParameterizedType listType = (ParameterizedType) field.getGenericType();
Class<?> parameterClass = (Class<?>) listType.getActualTypeArguments()[0];
try {
Object val = newInstanceOf(parameterClass);
if (val == null) {
return false;
}
list.add(index, val);
} catch (InstantiationException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
return true;
}
public static Class<?> getFieldSubType(Object object, Field field) {
if (field.getType().isArray()) {
Object arrValue;
try {
arrValue = field.get(object);
return arrValue.getClass().getComponentType();
} catch (IllegalArgumentException | IllegalAccessException ex) {
return null;
}
}
if (List.class.isAssignableFrom(field.getType())) {
ParameterizedType listType = (ParameterizedType) field.getGenericType();
return (Class<?>) listType.getActualTypeArguments()[0];
}
return null;
}
public static boolean addToArray(Object object, Field field, int index, boolean notnull) {
if (!field.getType().isArray()) {
return false;
}
Object arrValue;
try {
arrValue = field.get(object);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
Class componentClass = arrValue.getClass().getComponentType();
Object val = null;
if (!componentClass.isPrimitive()) {
try {
val = newInstanceOf(componentClass);
} catch (InstantiationException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
if (val == null) {
return false;
}
}
int originalSize = Array.getLength(arrValue);
Object copy = Array.newInstance(componentClass, originalSize + 1);
//Copy items before
for (int i = 0; i < index; i++) {
Array.set(copy, i, Array.get(arrValue, i));
}
if (val != null) {
Array.set(copy, index, val);
}
//Copy items after
for (int i = index; i < originalSize; i++) {
Array.set(copy, i + 1, Array.get(arrValue, i));
}
try {
field.set(object, copy);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
return true;
}
public static boolean addToField(Object object, Field field, int index, boolean notnull) {
if (List.class.isAssignableFrom(field.getType())) {
return addToList(object, field, index);
}
if (field.getType().isArray()) {
return addToArray(object, field, index, notnull);
}
return false;
}
public static boolean removeFromField(Object object, Field field, int index) {
if (List.class.isAssignableFrom(field.getType())) {
return removeFromList(object, field, index);
}
if (field.getType().isArray()) {
return removeFromArray(object, field, index);
}
return false;
}
public static boolean removeFromList(Object object, Field field, int index) {
List list;
try {
list = (List) field.get(object);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
if (index < 0 || index >= list.size()) {
return false;
}
list.remove(index);
return true;
}
public static boolean removeFromArray(Object object, Field field, int index) {
Object arrValue;
try {
arrValue = field.get(object);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
Class componentClass = arrValue.getClass().getComponentType();
int originalSize = Array.getLength(arrValue);
Object copy = Array.newInstance(componentClass, originalSize - 1);
int pos = 0;
//copy all before index
for (int i = 0; i < index; i++) {
Array.set(copy, pos, Array.get(arrValue, i));
pos++;
}
//copy all after index
for (int i = index + 1; i < originalSize; i++) {
Array.set(copy, pos, Array.get(arrValue, i));
pos++;
}
try {
field.set(object, copy);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
return true;
}
}