/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.node.NullNode;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
import org.apache.isis.core.metamodel.spec.ObjectSpecId;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
/**
* Similar to Isis' value encoding, but with additional support for JSON
* primitives.
*/
public final class JsonValueEncoder {
private JsonValueEncoder(){}
public static class ExpectedStringRepresentingValueException extends IllegalArgumentException {
private static final long serialVersionUID = 1L;
}
public static abstract class JsonValueConverter {
protected final String format;
protected final String xIsisFormat;
private final Class<?>[] classes;
public JsonValueConverter(String format, String xIsisFormat, Class<?>... classes) {
this.format = format;
this.xIsisFormat = xIsisFormat;
this.classes = classes;
}
public List<ObjectSpecId> getSpecIds() {
return Lists.newArrayList(Iterables.transform(Arrays.asList(classes), new Function<Class<?>, ObjectSpecId>() {
public ObjectSpecId apply(Class<?> cls) {
return new ObjectSpecId(cls.getName());
}
}));
}
/**
* The value, otherwise <tt>null</tt>.
*/
public abstract ObjectAdapter asAdapter(JsonRepresentation repr, String format);
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object value = unwrapAsObjectElseNullNode(objectAdapter);
repr.mapPut("value", value);
appendFormats(repr, this.format, this.xIsisFormat, suppressExtensions);
return value;
}
public Object asObject(ObjectAdapter objectAdapter, String format) {
return objectAdapter.getObject();
}
}
private static Map<ObjectSpecId, JsonValueConverter> converterBySpec = Maps.newLinkedHashMap();
private static void putConverter(JsonValueConverter jvc) {
final List<ObjectSpecId> specIds = jvc.getSpecIds();
for (ObjectSpecId specId : specIds) {
converterBySpec.put(specId, jvc);
}
}
static {
putConverter(new JsonValueConverter(null, "string", String.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
return adapterFor(repr.asString());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof String) {
final String str = (String) obj;
repr.mapPut("value", str);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter(null, "boolean", boolean.class, Boolean.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isBoolean()) {
return adapterFor(repr.asBoolean());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Boolean) {
final Boolean b = (Boolean) obj;
repr.mapPut("value", b);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("int", "byte", byte.class, Byte.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isNumber()) {
return adapterFor(repr.asNumber().byteValue());
}
if (repr.isInt()) {
return adapterFor((byte)(int)repr.asInt());
}
if (repr.isLong()) {
return adapterFor((byte)(long)repr.asLong());
}
if (repr.isBigInteger()) {
return adapterFor(repr.asBigInteger().byteValue());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Byte) {
final Byte b = (Byte) obj;
repr.mapPut("value", b);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("int", "short", short.class, Short.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isNumber()) {
return adapterFor(repr.asNumber().shortValue());
}
if (repr.isInt()) {
return adapterFor((short)(int)repr.asInt());
}
if (repr.isLong()) {
return adapterFor((short)(long)repr.asLong());
}
if (repr.isBigInteger()) {
return adapterFor(repr.asBigInteger().shortValue());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Short) {
final Short s = (Short) obj;
repr.mapPut("value", s);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("int", "int", int.class, Integer.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isInt()) {
return adapterFor(repr.asInt());
}
if (repr.isLong()) {
return adapterFor((int)(long)repr.asLong());
}
if (repr.isBigInteger()) {
return adapterFor(repr.asBigInteger().intValue());
}
if (repr.isNumber()) {
return adapterFor(repr.asNumber().intValue());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Integer) {
final Integer i = (Integer) obj;
repr.mapPut("value", i);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("int", "long", long.class, Long.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isLong()) {
return adapterFor(repr.asLong());
}
if (repr.isInt()) {
return adapterFor(repr.asInt());
}
if (repr.isBigInteger()) {
return adapterFor(repr.asBigInteger().longValue());
}
if (repr.isNumber()) {
return adapterFor(repr.asNumber().longValue());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Long) {
final Long l = (Long) obj;
repr.mapPut("value", l);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("decimal", "float", float.class, Float.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isDouble()) {
return adapterFor((float)(double)repr.asDouble());
}
if (repr.isNumber()) {
return adapterFor(repr.asNumber().floatValue());
}
if (repr.isLong()) {
return adapterFor((float)repr.asLong());
}
if (repr.isInt()) {
return adapterFor((float)repr.asInt());
}
if (repr.isBigInteger()) {
return adapterFor(repr.asBigInteger().floatValue());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Float) {
final Float f = (Float) obj;
repr.mapPut("value", f);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("decimal", "double", double.class, Double.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isDouble()) {
return adapterFor(repr.asDouble());
}
if (repr.isLong()) {
return adapterFor((double)repr.asLong());
}
if (repr.isInt()) {
return adapterFor((double)repr.asInt());
}
if (repr.isBigInteger()) {
return adapterFor(repr.asBigInteger().doubleValue());
}
if (repr.isBigDecimal()) {
return adapterFor(repr.asBigDecimal().doubleValue());
}
if (repr.isNumber()) {
return adapterFor(repr.asNumber().doubleValue());
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Double) {
final Double d = (Double) obj;
repr.mapPut("value", d);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter(null, "char", char.class, Character.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
final String str = repr.asString();
if(str != null && str.length()>0) {
return adapterFor(str.charAt(0));
}
}
// in case a char literal was provided
if(repr.isInt()) {
final Integer x = repr.asInt();
if(Character.MIN_VALUE <= x && x <= Character.MAX_VALUE) {
char c = (char) x.intValue();
return adapterFor(c);
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof Character) {
final Character c = (Character) obj;
repr.mapPut("value", c);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("big-integer(18)", "javamathbiginteger", BigInteger.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
return adapterFor(new BigInteger(repr.asString()));
}
if (repr.isBigInteger()) {
return adapterFor(repr.asBigInteger(format));
}
if (repr.isLong()) {
return adapterFor(BigInteger.valueOf(repr.asLong()));
}
if (repr.isInt()) {
return adapterFor(BigInteger.valueOf(repr.asInt()));
}
if (repr.isNumber()) {
return adapterFor(BigInteger.valueOf(repr.asNumber().longValue()));
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof BigInteger) {
final BigInteger bi = (BigInteger) obj;
repr.mapPut("value", bi);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, format != null? format: this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("big-decimal", "javamathbigdecimal", BigDecimal.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
return adapterFor(new BigDecimal(repr.asString()));
}
if (repr.isBigDecimal()) {
return adapterFor(repr.asBigDecimal(format));
}
if (repr.isBigInteger()) {
return adapterFor(new BigDecimal(repr.asBigInteger()));
}
if (repr.isDouble()) {
return adapterFor(BigDecimal.valueOf(repr.asDouble()));
}
if (repr.isLong()) {
return adapterFor(BigDecimal.valueOf(repr.asLong()));
}
if (repr.isInt()) {
return adapterFor(BigDecimal.valueOf(repr.asInt()));
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof BigDecimal) {
final BigDecimal bd = (BigDecimal) obj;
repr.mapPut("value", bd);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, format != null ? format : this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("date", "jodalocaldate", LocalDate.class){
// these formatters do NOT use withZoneUTC()
final List<DateTimeFormatter> formatters = Arrays.asList(
ISODateTimeFormat.date(),
ISODateTimeFormat.basicDate(),
DateTimeFormat.forPattern("yyyyMMdd"),
JsonRepresentation.yyyyMMdd
);
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
final String dateStr = repr.asString();
for (DateTimeFormatter formatter : formatters) {
try {
final LocalDate parsedDate = formatter.parseLocalDate(dateStr);
return adapterFor(parsedDate);
} catch (IllegalArgumentException ex) {
// fall through
}
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof LocalDate) {
final LocalDate date = (LocalDate) obj;
final String dateStr = formatters.get(0).print(date.toDateTimeAtStartOfDay());
repr.mapPut("value", dateStr);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("date-time", "jodalocaldatetime", LocalDateTime.class){
final List<DateTimeFormatter> formatters = Arrays.asList(
ISODateTimeFormat.dateTimeNoMillis().withZoneUTC(),
ISODateTimeFormat.dateTime().withZoneUTC(),
ISODateTimeFormat.basicDateTimeNoMillis().withZoneUTC(),
ISODateTimeFormat.basicDateTime().withZoneUTC(),
JsonRepresentation.yyyyMMddTHHmmssZ.withZoneUTC()
);
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
final String dateStr = repr.asString();
for (DateTimeFormatter formatter : formatters) {
try {
final LocalDateTime parsedDate = formatter.parseLocalDateTime(dateStr);
return adapterFor(parsedDate);
} catch (IllegalArgumentException ex) {
// fall through
}
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof LocalDateTime) {
final LocalDateTime date = (LocalDateTime) obj;
final String dateStr = formatters.get(0).print(date.toDateTime());
repr.mapPut("value", dateStr);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("date-time", "jodadatetime", DateTime.class){
final List<DateTimeFormatter> formatters = Arrays.asList(
ISODateTimeFormat.dateTimeNoMillis().withZoneUTC(),
ISODateTimeFormat.dateTime().withZoneUTC(),
ISODateTimeFormat.basicDateTimeNoMillis().withZoneUTC(),
ISODateTimeFormat.basicDateTime().withZoneUTC(),
JsonRepresentation.yyyyMMddTHHmmssZ.withZoneUTC()
);
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
final String dateStr = repr.asString();
for (DateTimeFormatter formatter : formatters) {
try {
final DateTime parsedDate = formatter.parseDateTime(dateStr);
return adapterFor(parsedDate);
} catch (IllegalArgumentException ex) {
// fall through
}
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof DateTime) {
final DateTime date = (DateTime) obj;
final String dateStr = formatters.get(0).print(date.toDateTime());
repr.mapPut("value", dateStr);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("date-time", "javautildate", java.util.Date.class){
final List<DateTimeFormatter> formatters = Arrays.asList(
ISODateTimeFormat.dateTimeNoMillis().withZoneUTC(),
ISODateTimeFormat.dateTime().withZoneUTC(),
ISODateTimeFormat.basicDateTimeNoMillis().withZoneUTC(),
ISODateTimeFormat.basicDateTime().withZoneUTC(),
JsonRepresentation.yyyyMMddTHHmmssZ.withZoneUTC()
);
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
final String dateStr = repr.asString();
for (DateTimeFormatter formatter : formatters) {
try {
final DateTime parseDateTime = formatter.parseDateTime(dateStr);
final java.util.Date parsedDate = parseDateTime.toDate();
return adapterFor(parsedDate);
} catch (IllegalArgumentException ex) {
// fall through
}
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof java.util.Date) {
final java.util.Date date = (java.util.Date) obj;
final DateTimeFormatter dateTimeFormatter = formatters.get(0);
final String dateStr = dateTimeFormatter.print(new DateTime(date));
repr.mapPut("value", dateStr);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("date", "javasqldate", java.sql.Date.class){
final List<DateTimeFormatter> formatters = Arrays.asList(
ISODateTimeFormat.date().withZoneUTC(),
ISODateTimeFormat.basicDate().withZoneUTC(),
JsonRepresentation.yyyyMMdd.withZoneUTC()
);
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
final String dateStr = repr.asString();
for (DateTimeFormatter formatter : formatters) {
try {
final DateTime parseDateTime = formatter.parseDateTime(dateStr);
final java.sql.Date parsedDate = new java.sql.Date(parseDateTime.getMillis());
return adapterFor(parsedDate);
} catch (IllegalArgumentException ex) {
// fall through
}
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof java.sql.Date) {
final java.sql.Date date = (java.sql.Date) obj;
final String dateStr = formatters.get(0).print(new DateTime(date));
repr.mapPut("value", dateStr);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("time", "javasqltime", java.sql.Time.class){
final List<DateTimeFormatter> formatters = Arrays.asList(
ISODateTimeFormat.hourMinuteSecond().withZoneUTC(),
ISODateTimeFormat.basicTimeNoMillis().withZoneUTC(),
ISODateTimeFormat.basicTime().withZoneUTC(),
JsonRepresentation._HHmmss.withZoneUTC()
);
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isString()) {
final String dateStr = repr.asString();
for (DateTimeFormatter formatter : formatters) {
try {
final DateTime parseDateTime = formatter.parseDateTime(dateStr);
final java.sql.Time parsedTime = new java.sql.Time(parseDateTime.getMillis());
return adapterFor(parsedTime);
} catch (IllegalArgumentException ex) {
// fall through
}
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof java.sql.Time) {
final java.sql.Time date = (java.sql.Time) obj;
final String dateStr = formatters.get(0).print(new DateTime(date));
repr.mapPut("value", dateStr);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
putConverter(new JsonValueConverter("utc-millisec", "javasqltimestamp", java.sql.Timestamp.class){
@Override
public ObjectAdapter asAdapter(JsonRepresentation repr, String format) {
if (repr.isLong()) {
final Long millis = repr.asLong();
final java.sql.Timestamp parsedTimestamp = new java.sql.Timestamp(millis);
return adapterFor(parsedTimestamp);
}
if (repr.isString()) {
final String dateStr = repr.asString();
try {
final Long parseMillis = Long.parseLong(dateStr);
final java.sql.Timestamp parsedTimestamp = new java.sql.Timestamp(parseMillis);
return adapterFor(parsedTimestamp);
} catch (IllegalArgumentException ex) {
// fall through
}
}
return null;
}
@Override
public Object appendValueAndFormat(ObjectAdapter objectAdapter, String format, JsonRepresentation repr, boolean suppressExtensions) {
final Object obj = unwrapAsObjectElseNullNode(objectAdapter);
if(obj instanceof java.sql.Timestamp) {
final java.sql.Timestamp date = (java.sql.Timestamp) obj;
final long millisStr = date.getTime();
repr.mapPut("value", millisStr);
} else {
repr.mapPut("value", obj);
}
appendFormats(repr, this.format, xIsisFormat, suppressExtensions);
return obj;
}
});
}
public static ObjectAdapter asAdapter(final ObjectSpecification objectSpec, final JsonRepresentation argValueRepr, final String format) {
if(argValueRepr == null) {
return null;
}
if (objectSpec == null) {
throw new IllegalArgumentException("ObjectSpecification is required");
}
if (!argValueRepr.isValue()) {
throw new IllegalArgumentException("Representation must be of a value");
}
final EncodableFacet encodableFacet = objectSpec.getFacet(EncodableFacet.class);
if (encodableFacet == null) {
String reason = "ObjectSpec expected to have an EncodableFacet";
throw new IllegalArgumentException(reason);
}
final ObjectSpecId specId = objectSpec.getSpecId();
final JsonValueConverter jvc = converterBySpec.get(specId);
if(jvc == null) {
// best effort
if (argValueRepr.isString()) {
final String argStr = argValueRepr.asString();
return encodableFacet.fromEncodedString(argStr);
}
throw new IllegalArgumentException("Unable to parse value");
}
final ObjectAdapter asAdapter = jvc.asAdapter(argValueRepr, format);
if(asAdapter != null) {
return asAdapter;
}
// last attempt
if (argValueRepr.isString()) {
final String argStr = argValueRepr.asString();
try {
return encodableFacet.fromEncodedString(argStr);
} catch(TextEntryParseException ex) {
throw new IllegalArgumentException(ex.getMessage());
}
}
throw new IllegalArgumentException("Could not parse value '" + argValueRepr.asString() + "' as a " + objectSpec.getFullIdentifier());
}
public static Object appendValueAndFormat(ObjectSpecification objectSpec, ObjectAdapter objectAdapter, JsonRepresentation repr, String format, boolean suppressExtensions) {
final JsonValueConverter jvc = converterBySpec.get(objectSpec.getSpecId());
if(jvc != null) {
return jvc.appendValueAndFormat(objectAdapter, format, repr, suppressExtensions);
} else {
final EncodableFacet encodableFacet = objectSpec.getFacet(EncodableFacet.class);
if (encodableFacet == null) {
throw new IllegalArgumentException("objectSpec expected to have EncodableFacet");
}
Object value = objectAdapter != null? encodableFacet.toEncodedString(objectAdapter): NullNode.getInstance();
repr.mapPut("value", value);
appendFormats(repr, "string", "string", suppressExtensions);
return value;
}
}
public static Object asObject(final ObjectAdapter objectAdapter, final String format) {
if (objectAdapter == null) {
throw new IllegalArgumentException("objectAdapter cannot be null");
}
final ObjectSpecification objectSpec = objectAdapter.getSpecification();
final JsonValueConverter jvc = converterBySpec.get(objectSpec.getSpecId());
if(jvc != null) {
return jvc.asObject(objectAdapter, format);
}
// else
final EncodableFacet encodableFacet = objectSpec.getFacet(EncodableFacet.class);
if (encodableFacet == null) {
throw new IllegalArgumentException("objectSpec expected to have EncodableFacet");
}
return encodableFacet.toEncodedString(objectAdapter);
}
private static void appendFormats(JsonRepresentation repr, String format, String xIsisFormat, boolean suppressExtensions) {
if(format != null) {
repr.mapPut("format", format);
}
if(!suppressExtensions && xIsisFormat != null) {
repr.mapPut("extensions.x-isis-format", xIsisFormat);
}
}
private static Object unwrapAsObjectElseNullNode(ObjectAdapter objectAdapter) {
return objectAdapter != null? objectAdapter.getObject(): NullNode.getInstance();
}
private static ObjectAdapter adapterFor(Object value) {
return getAdapterManager().adapterFor(value);
}
private static AdapterManager testAdapterManager;
// for testing purposes only
static void testSetAdapterManager(AdapterManager adapterManager) {
JsonValueEncoder.testAdapterManager = adapterManager;
}
public static AdapterManager getAdapterManager() {
return testAdapterManager != null? testAdapterManager: getPersistenceSession();
}
private static PersistenceSession getPersistenceSession() {
return getIsisSessionFactory().getCurrentSession().getPersistenceSession();
}
static IsisSessionFactory getIsisSessionFactory() {
return IsisContext.getSessionFactory();
}
}