/** * Marshals given object to provided Writer or OutputStream. * * @param object object to marshall * @param jsonGenerator generator to use */ public void marshall(Object object, JsonGenerator jsonGenerator) { try { final ContainerModel model = new ContainerModel(runtimeType != null ? runtimeType : object.getClass(), null); serializeRoot(object, jsonGenerator, model); } catch (JsonbException e) { logger.severe(e.getMessage()); throw e; } finally { try { jsonGenerator.close(); } catch (JsonGenerationException jge) { logger.severe(jge.getMessage()); } } }
/** * Propagates properties from JsonbConfig to JSONP generator / parser factories. * * @param jsonbConfig jsonb config * @return properties for JSONP generator / parser */ protected Map<String, ?> createJsonpProperties(JsonbConfig jsonbConfig) { //JSONP 1.0 actually ignores the value, just checks the key is present. Only set if JsonbConfig.FORMATTING is true. final Optional<Object> property = jsonbConfig.getProperty(JsonbConfig.FORMATTING); final Map<String, Object> factoryProperties = new HashMap<>(); if (property.isPresent()) { final Object value = property.get(); if (!(value instanceof Boolean)) { throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_FORMATTING_ILLEGAL_VALUE)); } if ((Boolean) value) { factoryProperties.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE); } return factoryProperties; } return factoryProperties; }
@Override protected void acceptMethod(Method method, OperationMode mode) { try { switch (mode) { case GET: getHandle = MethodHandles.lookup().unreflect(method); break; case SET: setHandle = MethodHandles.lookup().unreflect(method); break; default: throw new IllegalStateException("Unknown mode"); } } catch (IllegalAccessException e) { throw new JsonbException(Messages.getMessage(MessageKeys.CREATING_HANDLES), e); } }
@Override protected void acceptField(Field field, OperationMode mode) { try { switch (mode) { case GET: getHandle = MethodHandles.lookup().unreflectGetter(field); break; case SET: setHandle = MethodHandles.lookup().unreflectSetter(field); break; default: throw new IllegalStateException("Unknown mode"); } } catch (IllegalAccessException e) { throw new JsonbException(Messages.getMessage(MessageKeys.CREATING_HANDLES), e); } }
private Class<?> getInterfaceMappedType(Class<?> interfaceType) { if (interfaceType.isInterface()) { Class implementationClass = null; //annotation if (getModel().getCustomization() instanceof PropertyCustomization) { implementationClass = ((PropertyCustomization) getModel().getCustomization()).getImplementationClass(); } //JsonbConfig if (implementationClass == null) { implementationClass = jsonbContext.getConfigProperties().getUserTypeMapping().get(interfaceType); } if (implementationClass != null) { if (!interfaceType.isAssignableFrom(implementationClass)) { throw new JsonbException(Messages.getMessage(MessageKeys.IMPL_CLASS_INCOMPATIBLE, implementationClass, interfaceType)); } return implementationClass; } } return null; }
@Override protected Double deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { switch (jsonValue) { case NAN: return Double.NaN; case POSITIVE_INFINITY: return Double.POSITIVE_INFINITY; case NEGATIVE_INFINITY: return Double.NEGATIVE_INFINITY; } return deserializeFormatted(jsonValue, false, unmarshaller.getJsonbContext()) .map(num -> Double.parseDouble(num.toString())) .orElseGet(() -> { try { return Double.parseDouble(jsonValue); } catch (NumberFormatException e) { throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, Double.class)); } }); }
protected void deserializeInternal(JsonbParser parser, Unmarshaller context) { parserContext = moveToFirst(parser); while (parser.hasNext()) { final JsonParser.Event event = parser.next(); switch (event) { case START_OBJECT: case START_ARRAY: case VALUE_STRING: case VALUE_NUMBER: case VALUE_FALSE: case VALUE_TRUE: deserializeNext(parser, context); break; case KEY_NAME: break; case VALUE_NULL: appendResult(null); break; case END_OBJECT: case END_ARRAY: return; default: throw new JsonbException(Messages.getMessage(MessageKeys.NOT_VALUE_TYPE, event)); } } }
protected final Optional<Number> deserializeFormatted(String jsonValue, boolean integerOnly, JsonbContext jsonbContext) { if (getModel() == null || getModel().getCustomization() == null || getModel().getCustomization().getDeserializeNumberFormatter() == null) { return Optional.empty(); } final JsonbNumberFormatter numberFormat = getModel().getCustomization().getDeserializeNumberFormatter(); //consider synchronizing on format instance or per thread cache. final NumberFormat format = NumberFormat.getInstance(jsonbContext.getConfigProperties().getLocale(numberFormat.getLocale())); ((DecimalFormat)format).applyPattern(numberFormat.getFormat()); format.setParseIntegerOnly(integerOnly); try { return Optional.of(format.parse(jsonValue)); } catch (ParseException e) { throw new JsonbException(Messages.getMessage(MessageKeys.PARSING_NUMBER, jsonValue, numberFormat.getFormat())); } }
@Override @SuppressWarnings("unchecked") public T deserialize(JsonParser parser, DeserializationContext context, Type rtType) { Unmarshaller unmarshaller = (Unmarshaller) context; unmarshaller.setCurrent(this); try { unmarshaller.getJsonbContext().addProcessedType(adapterInfo.getBindingType()); final A result = adaptedTypeDeserializer.deserialize(parser, context, rtType); final T adapted = ((JsonbAdapter<T, A>) adapterInfo.getAdapter()).adaptFromJson(result); unmarshaller.setCurrent(wrapperItem); return adapted; } catch (Exception e) { throw new JsonbException(Messages.getMessage(MessageKeys.ADAPTER_EXCEPTION, adapterInfo.getBindingType(), adapterInfo.getToType(), adapterInfo.getAdapter().getClass()), e); } finally { unmarshaller.getJsonbContext().removeProcessedType(adapterInfo.getBindingType()); } }
@Override public JsonValue deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { final JsonParser.Event next = ((JsonbRiParser)parser).getLastEvent(); switch (next) { case VALUE_TRUE: return JsonValue.TRUE; case VALUE_FALSE: return JsonValue.FALSE; case VALUE_NULL: return JsonValue.NULL; case VALUE_STRING: case VALUE_NUMBER: return parser.getValue(); default: throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Unknown JSON value: "+next)); } }
@Override public T deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { final JsonbDateFormatter formatter = getJsonbDateFormatter(unmarshaller.getJsonbContext()); if (JsonbDateFormat.TIME_IN_MILLIS.equals(formatter.getFormat())) { return fromInstant(Instant.ofEpochMilli(Long.parseLong(jsonValue))); } else if (formatter.getDateTimeFormatter() != null) { return parseWithFormatterInternal(jsonValue, formatter.getDateTimeFormatter()); } else { DateTimeFormatter configDateTimeFormatter = unmarshaller.getJsonbContext().getConfigProperties().getConfigDateFormatter().getDateTimeFormatter(); if (configDateTimeFormatter != null) { return parseWithFormatterInternal(jsonValue, configDateTimeFormatter); } } final boolean strictIJson = unmarshaller.getJsonbContext().getConfigProperties().isStrictIJson(); if (strictIJson) { return parseWithFormatterInternal(jsonValue, JsonbDateFormatter.IJSON_DATE_FORMATTER); } try { return parseDefault(jsonValue, unmarshaller.getJsonbContext().getConfigProperties().getLocale(formatter.getLocale())); } catch (DateTimeParseException e) { throw new JsonbException(Messages.getMessage(MessageKeys.DATE_PARSE_ERROR, jsonValue), e); } }
private JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Class<?> clazz) { if (existing != null) { throw new JsonbException(Messages.getMessage(MessageKeys.MULTIPLE_JSONB_CREATORS, clazz)); } final Parameter[] parameters = executable.getParameters(); CreatorModel[] creatorModels = new CreatorModel[parameters.length]; for (int i=0; i<parameters.length; i++) { final Parameter parameter = parameters[i]; final JsonbProperty jsonbPropertyAnnotation = parameter.getAnnotation(JsonbProperty.class); if (jsonbPropertyAnnotation != null && !jsonbPropertyAnnotation.value().isEmpty()) { creatorModels[i] = new CreatorModel(jsonbPropertyAnnotation.value(), parameter, jsonbContext); } else { creatorModels[i] = new CreatorModel(parameter.getName(), parameter, jsonbContext); } } return new JsonbCreator(executable, creatorModels); }
private void checkPropertyNameClash(List<PropertyModel> collectedProperties, Class cls) { final List<PropertyModel> checkedProperties = new ArrayList<>(); for (PropertyModel collectedPropertyModel : collectedProperties) { for (PropertyModel checkedPropertyModel : checkedProperties) { if ((checkedPropertyModel.getReadName().equals(collectedPropertyModel.getReadName()) && checkedPropertyModel.isReadable() && collectedPropertyModel.isReadable()) || (checkedPropertyModel.getWriteName().equals(collectedPropertyModel.getWriteName())) && checkedPropertyModel.isWritable() && collectedPropertyModel.isWritable()) { throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_NAME_CLASH, checkedPropertyModel.getPropertyName(), collectedPropertyModel.getPropertyName(), cls.getName())); } } checkedProperties.add(collectedPropertyModel); } }
private PropOrderStrategy initOrderStrategy() { final Optional<Object> property = jsonbConfig.getProperty(JsonbConfig.PROPERTY_ORDER_STRATEGY); if (property.isPresent()) { final Object strategy = property.get(); if (!(strategy instanceof String)) { throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_ORDER, strategy)); } switch ((String) strategy) { case PropertyOrderStrategy.LEXICOGRAPHICAL: return new LexicographicalOrderStrategy(); case PropertyOrderStrategy.REVERSE: return new ReverseOrderStrategy(); case PropertyOrderStrategy.ANY: return new AnyOrderStrategy(); default: throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_ORDER, strategy)); } } //default by spec return new LexicographicalOrderStrategy(); }
private PropertyNamingStrategy initPropertyNamingStrategy() { final Optional<Object> property = jsonbConfig.getProperty(JsonbConfig.PROPERTY_NAMING_STRATEGY); if (!property.isPresent()) { return new IdentityStrategy(); } Object propertyNamingStrategy = property.get(); if (propertyNamingStrategy instanceof String) { String namingStrategyName = (String) propertyNamingStrategy; final PropertyNamingStrategy foundNamingStrategy = DefaultNamingStrategies.getStrategy(namingStrategyName); if (foundNamingStrategy == null) { throw new JsonbException("No property naming strategy was found for: " + namingStrategyName); } return foundNamingStrategy; } if (!(propertyNamingStrategy instanceof PropertyNamingStrategy)) { throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_NAMING_STRATEGY_INVALID)); } return (PropertyNamingStrategy) property.get(); }
/** * Same problem as above but now field is public, so clash takes place. */ @Test public void testConflictingProperties() { ConflictingProperties conflictingProperties = new ConflictingProperties(); conflictingProperties.setDOI("DOI value"); Jsonb jsonb = JsonbBuilder.create(new JsonbConfig() ); try { jsonb.toJson(conflictingProperties); fail(); } catch (JsonbException e) { if (!e.getMessage().equals("Property DOI clashes with property doi by read or write name in class org.eclipse.yasson.customization.JsonbPropertyTest$ConflictingProperties.")) { throw e; } } }
/** * Tests clash with property altered by naming strategy. */ @Test public void testConflictingWithUpperCamelStrategy() { ConflictingWithUpperCamelStrategy pojo = new ConflictingWithUpperCamelStrategy(); pojo.setDOI("DOI value"); Jsonb jsonb = JsonbBuilder.create(); String json = jsonb.toJson(pojo); Assert.assertEquals("{\"Doi\":\"DOI value\",\"doi\":\"DOI value\"}", json); jsonb = JsonbBuilder.create(new JsonbConfig() .withPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE)); try { jsonb.toJson(pojo); fail(); } catch (JsonbException e) { if (!e.getMessage().equals("Property DOI clashes with property doi by read or write name in class org.eclipse.yasson.customization.JsonbPropertyTest$ConflictingWithUpperCamelStrategy.")) { throw e; } } }
@Test public void testUnmarshallToUnsupportedInterface() { ClassWithUnsupportedFields unsupported = new ClassWithUnsupportedFields(); unsupported.customInterface = new CustomUnsupportedInterface() { private String value = "value1"; @Override public String getValue() { return value; } @Override public void setValue(String value) { throw new IllegalStateException("Not supposed to be called."); } }; String expected = "{\"customInterface\":{\"value\":\"value1\"}}"; assertEquals(expected, jsonb.toJson(unsupported)); try { jsonb.fromJson(expected, ClassWithUnsupportedFields.class); fail("Should report an error"); } catch (JsonbException e) { assertTrue(e.getMessage().startsWith("Can't infer a type")); } }
@Override public <T> T fromJson(final String str, final Class<T> type) throws JsonbException { try { if (isArray(type)) { return delegate.readTypedArray(new StringReader(str), type.getComponentType(), type); } else if (Collection.class.isAssignableFrom(type)) { return (T) delegate.readCollection(new StringReader(str), new JohnzonParameterizedType(type, Object.class)); } final Type mappingType = unwrapPrimitiveOptional(type); final Object object = delegate.readObject(str, mappingType); if (mappingType != type) { return wrapPrimitiveOptional(object, type); } return (T) object; } catch (final MapperException me) { throw new JsonbException(me.getMessage(), me); } }
@Override public <T> T fromJson(final String str, final Type runtimeType) throws JsonbException { try { if (isArray(runtimeType)) { final Class cast = Class.class.cast(runtimeType); return (T) delegate.readTypedArray(new StringReader(str), cast.getComponentType(), cast); } else if (isCollection(runtimeType)) { return (T) delegate.readCollection(new StringReader(str), ParameterizedType.class.cast(runtimeType)); } final Type mappingType = unwrapPrimitiveOptional(runtimeType); final Object object = delegate.readObject(str, mappingType); if (mappingType != runtimeType) { return wrapPrimitiveOptional(object, runtimeType); } return (T) object; } catch (final MapperException me) { throw new JsonbException(me.getMessage(), me); } }
@Override public <T> T fromJson(final Reader reader, final Class<T> type) throws JsonbException { try { if (isArray(type)) { return delegate.readTypedArray(reader, type.getComponentType(), type); } else if (Collection.class.isAssignableFrom(type)) { return (T) delegate.readCollection(reader, new JohnzonParameterizedType(type, Object.class)); } final Type mappingType = unwrapPrimitiveOptional(type); final Object object = delegate.readObject(reader, mappingType); if (mappingType != type) { return wrapPrimitiveOptional(object, type); } return (T) object; } catch (final MapperException me) { throw new JsonbException(me.getMessage(), me); } }
@Override public <T> T fromJson(final Reader reader, final Type runtimeType) throws JsonbException { try { if (isArray(runtimeType)) { final Class<T> type = Class.class.cast(runtimeType); return delegate.readTypedArray(reader, type.getComponentType(), type); } else if (isCollection(runtimeType)) { return (T) delegate.readCollection(reader, ParameterizedType.class.cast(runtimeType)); } final Type mappingType = unwrapPrimitiveOptional(runtimeType); final Object object = delegate.readObject(reader, mappingType); if (mappingType != runtimeType) { return wrapPrimitiveOptional(object, runtimeType); } return (T) object; } catch (final MapperException me) { throw new JsonbException(me.getMessage(), me); } }
@Override public <T> T fromJson(final InputStream stream, final Class<T> type) throws JsonbException { try { if (isArray(type)) { return delegate.readTypedArray(stream, type.getComponentType(), type); } else if (Collection.class.isAssignableFrom(type)) { return (T) delegate.readCollection(stream, new JohnzonParameterizedType(type, Object.class)); } final Type mappingType = unwrapPrimitiveOptional(type); final Object object = delegate.readObject(stream, mappingType); if (mappingType != type) { return wrapPrimitiveOptional(object, type); } return (T) object; } catch (final MapperException me) { throw new JsonbException(me.getMessage(), me); } }
@Override public <T> T fromJson(final InputStream stream, final Type runtimeType) throws JsonbException { try { if (isArray(runtimeType)) { final Class<T> type = Class.class.cast(runtimeType); return delegate.readTypedArray(stream, type.getComponentType(), type); } else if (isCollection(runtimeType)) { return (T) delegate.readCollection(stream, ParameterizedType.class.cast(runtimeType)); } final Type mappingType = unwrapPrimitiveOptional(runtimeType); final Object object = delegate.readObject(stream, mappingType); if (mappingType != runtimeType) { return wrapPrimitiveOptional(object, runtimeType); } return (T) object; } catch (final MapperException me) { throw new JsonbException(me.getMessage(), me); } }
@Override public String toJson(final Object inObject) throws JsonbException { try { final Object object = unwrapOptional(inObject); if (object == null) { return "null"; } if (isArray(object.getClass())) { return delegate.writeArrayAsString(toArray(object)); } else if (Collection.class.isInstance(object)) { return delegate.writeArrayAsString(Collection.class.cast(object)); } return delegate.writeObjectAsString(object); } catch (final MapperException me) { throw new JsonbException(me.getMessage(), me); } }
public static void fromJsonInstantiation() { //public or protected constructor must be present try { POJOWithoutDefaultArgConstructor pojo = JSONB.fromJson("{\"id\":\"1\"}", POJOWithoutDefaultArgConstructor.class); fail(); } catch (JsonbException e) { } /* TBD: protected or private is the same try { JSONB.fromJson("{\"id\":\"1\"}", POJOWithPrivateConstructor.class); fail(); } catch (JsonbException e) { } */ }
@Test public void givenDateInJsonDocument_shouldThrowException() { String json = "{\"published\":\"10/10/2018\",\"author\":\"Alex Theedom\",\"title\":\"Fun with JSON-B\",\"id\":\"ABC-123-XYZ\"}"; assertThatThrownBy(() -> JsonbBuilder.create().fromJson(json, Book.class) ).isInstanceOf(JsonbException.class) .hasMessageContaining("Error parsing date from value: 10/10/2018"); }
private static ParameterizedType findParameterizedSuperclass(Type type) { if (type == null || type instanceof ParameterizedType) { return (ParameterizedType) type; } if (!(type instanceof Class)) { throw new JsonbException(Messages.getMessage(MessageKeys.RESOLVE_PARAMETRIZED_TYPE, type)); } return findParameterizedSuperclass(((Class) type).getGenericSuperclass()); }
/** * Serializes root element. * * @param <T> Root type * @param root Root. * @param generator JSON generator. * @param model Binding model. */ @SuppressWarnings("unchecked") public <T> void serializeRoot(T root, JsonGenerator generator, JsonBindingModel model) { final JsonbSerializer<T> rootSerializer = (JsonbSerializer<T>) getRootSerializer(root.getClass(), model); if (jsonbContext.getConfigProperties().isStrictIJson() && rootSerializer instanceof AbstractValueTypeSerializer) { throw new JsonbException(Messages.getMessage(MessageKeys.IJSON_ENABLED_SINGLE_VALUE)); } rootSerializer.serialize(root, generator, this); }
@Override public String toJson(Object object) throws JsonbException { StringWriter writer = new StringWriter(); final JsonGenerator generator = writerGenerator(writer); new Marshaller(jsonbContext).marshall(object, generator); return writer.toString(); }
@Override public String toJson(Object object, Type type) throws JsonbException { StringWriter writer = new StringWriter(); final JsonGenerator generator = writerGenerator(writer); new Marshaller(jsonbContext, type).marshall(object, generator); return writer.toString(); }
@Override public void moveTo(JsonParser.Event required) { if (!level.empty() && level.peek().getLastEvent() == required) { return; } final Event next = next(); if (next == required) { return; } throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Event " + required + " not found." + getLastDataMsg())); }
private Event moveTo(Event... events) { if (!level.empty() && contains(events, level.peek().getLastEvent())) { return level.peek().getLastEvent(); } final Event next = next(); if (contains(events, next)) { return next; } throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Parser event ["+Arrays.toString(events)+"] not found." + getLastDataMsg())); }
/** * {@inheritDoc} */ @Override public void setValue(Object object, Object value) { try { setHandle.invoke(object, value); } catch (Throwable throwable) { throw new JsonbException(Messages.getMessage(MessageKeys.SETTING_VALUE_WITH, setHandle), throwable); } }
/** * {@inheritDoc} */ @Override public Object getValue(Object object) { try { return getHandle.invoke(object); } catch (Throwable throwable) { throw new JsonbException(Messages.getMessage(MessageKeys.GETTING_VALUE_WITH, getHandle), throwable); } }
/** * Create instance by either constructor or factory method, with provided parameter values and a Class to call on. * * @param params parameters to be passed into constructor / factory method * @param on class to call onto * @param <T> Type of class / instance * @return instance */ @SuppressWarnings("unchecked") public <T> T call(Object[] params, Class<T> on) { try { if (executable instanceof Constructor) { return ((Constructor<T>) executable).newInstance(params); } else { return (T) ((Method) executable).invoke(on, params); } } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { throw new JsonbException(Messages.getMessage(MessageKeys.ERROR_CALLING_JSONB_CREATOR, on), e); } }
/** * Sets a value with reflection on {@link java.lang.reflect.Field field} or {@link java.lang.reflect.Method setter}. * * @param object object to invoke set value on, not null. * @param value object to be set, nullable. * @throws JsonbException if reflection fails. */ final void setValue(Object object, Object value) { Objects.requireNonNull(object); try { internalSetValue(object, value); } catch (InvocationTargetException | IllegalAccessException e) { throw new JsonbException("Error getting value on: " + object, e); } }
/** * Get a value with reflection on {@link java.lang.reflect.Field field} or {@link java.lang.reflect.Method getter}. * * @param object object to invoke get value on, not null. * @throws JsonbException if reflection fails. * @return value */ final Object getValue(Object object) { Objects.requireNonNull(object); try { return internalGetValue(object); } catch (InvocationTargetException | IllegalAccessException e) { throw new JsonbException("Error getting value on: " + object, e); } }
/** * Adds annotation. * * @param annotation Annotation to add. */ public void putAnnotation(Annotation annotation) { if (annotations.containsKey(annotation.annotationType())) { throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Annotation already present: " + annotation)); } annotations.put(annotation.annotationType(), annotation); }
/** * Extracts type from first not null element: * Field, Getter, Setter. * * @return type of a property */ public Type getPropertyType() { if (getField() != null) { return getField().getGenericType(); } else if (getGetter() != null) { return getGetter().getGenericReturnType(); } else if (getSetter() != null) { Type[] genericParameterTypes = getSetter().getGenericParameterTypes(); if (genericParameterTypes.length != 1) { throw new JsonbException("Invalid count of arguments for setter: " + getSetter()); } return genericParameterTypes[0]; } throw new JsonbException("Empty property: " + name); }