All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.lib.json.ObjectHandler Maven / Gradle / Ivy

Go to download

A main program (executable JAR) that will listen to port 29998. At first, it can only answer that it is an Envoy (a limited agent). The only function it supports is installing a -runpath. It will then create a framework + agent and transfer the connection to the just installed agent who will then install the bundles. This JAR is a main command for JPM called bndremote. In JPM, it will start up with debug enabled. This JAR does some highly complicated class loading wizardy to ensure that it does not enforce any constraints on the -runpath.

The newest version!
package aQute.lib.json;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

public class ObjectHandler extends Handler {
	@SuppressWarnings("rawtypes")
	final Class		rawClass;
	final Field		fields[];
	final Type		types[];
	final Object	defaults[];
	final Field		extra;
	final Supplier	factory;

	ObjectHandler(JSONCodec codec, Class c) throws Exception {
		rawClass = c;
		factory = newInstanceFunction(c);
		List fields = new ArrayList<>();
		for (Field f : c.getFields()) {
			if (Modifier.isStatic(f.getModifiers()))
				continue;
			fields.add(f);
		}

		this.fields = fields.toArray(new Field[0]);

		// Sort the fields so the output is canonical
		Arrays.sort(this.fields, (o1, o2) -> o1.getName()
			.compareTo(o2.getName()));

		types = new Type[this.fields.length];
		defaults = new Object[this.fields.length];

		Field x = null;
		for (int i = 0; i < this.fields.length; i++) {
			if (this.fields[i].getName()
				.equals("__extra"))
				x = this.fields[i];
			types[i] = this.fields[i].getGenericType();
		}
		if (x != null && Map.class.isAssignableFrom(x.getType()))
			extra = x;
		else
			extra = null;

		try {
			Object template = factory.get();

			for (int i = 0; i < this.fields.length; i++) {
				defaults[i] = getField(this.fields[i], template);
			}
		} catch (Exception e) {
			// Ignore
		}
	}

	@Override
	public void encode(Encoder app, Object object, Map visited) throws Exception {
		app.append("{");
		app.indent();
		String del = "";
		for (int i = 0; i < fields.length; i++)
			try {
				Field field = fields[i];
				String actualName = JSONCodec.keyword(field.getName());
				if (actualName.startsWith("__"))
					continue;

				Object value = getField(fields[i], object);
				if (!app.writeDefaults) {
					if (value == defaults[i])
						continue;

					if (value != null && value.equals(defaults[i]))
						continue;
				}

				app.append(del);
				if (!del.isEmpty()) {
					app.linebreak();
				}
				StringHandler.string(app, actualName);
				app.append(":");
				app.encode(value, types[i], visited);
				del = ",";
			} catch (Exception e) {
				throw new IllegalArgumentException(fields[i].getName() + ":", e);
			}
		app.undent();
		app.append("}");
	}

	@Override
	public Object decodeObject(Decoder r) throws Exception {
		assert r.current() == '{';
		@SuppressWarnings("unchecked")
		Object targetObject = factory.get();

		int c = r.next();
		while (r.codec.isStartCharacter(c)) {

			// Get key
			String key = r.codec.parseString(r);

			// Get separator
			c = r.skipWs();
			if (c != ':')
				throw new IllegalArgumentException("Expected ':' but got " + (char) c);

			c = r.next();

			// Get value

			Field f = getField(key);
			if (f != null) {
				// We have a field and thus a type
				Object value = r.codec.decode(f.getGenericType(), r);
				if (value != null || !r.codec.ignorenull) {
					if (Modifier.isFinal(f.getModifiers()))
						throw new IllegalArgumentException("Field " + f + " is final");

					setField(f, targetObject, value);
				}
			} else {
				// No field, but may extra is defined
				if (extra == null) {
					if (r.strict)
						throw new IllegalArgumentException("No such field " + key);
					Object value = r.codec.decode(null, r);
					r.getExtra()
						.put(rawClass.getName() + "." + key, value);
				} else {

					@SuppressWarnings("unchecked")
					Map map = (Map) getField(extra, targetObject);
					if (map == null) {
						map = new LinkedHashMap<>();
						setField(extra, targetObject, map);
					}
					Object value = r.codec.decode(null, r);
					map.put(key, value);
				}
			}

			c = r.skipWs();

			if (c == '}')
				break;

			if (c == ',') {
				c = r.next();
				continue;
			}

			if (r.codec.promiscuous && r.isEof()) {
				r.codec.fishy.incrementAndGet();
				return targetObject;
			}

			throw new IllegalArgumentException(
				"Invalid character in parsing object, expected } or , but found " + (char) c);
		}
		assert r.current() == '}';
		r.read(); // skip closing
		return targetObject;
	}

	private Field getField(String key) {
		for (Field field : fields) {
			if (key.equals(field.getName()))
				return field;
		}
		String fixup = JSONCodec.name(key);
		for (Field field : fields) {
			if (fixup.equals(field.getName()))
				return field;
		}
		return null;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy