de.javagl.jgltf.model.io.JacksonUtils Maven / Gradle / Ivy
/*
* www.javagl.de - JglTF
*
* Copyright 2015-2016 Marco Hutter - http://www.javagl.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package de.javagl.jgltf.model.io;
import java.io.IOException;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.logging.Logger;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.module.SimpleModule;
/**
* Utility methods related to Jackson JSON parsing.
*
* This class should not be considered as part of the API.
*/
public class JacksonUtils
{
/**
* The logger used in this class
*/
private static final Logger logger =
Logger.getLogger(JacksonUtils.class.getName());
/**
* An consumer for {@link JsonError}s that prints log messages
*/
private static final Consumer LOG_JSON_ERROR_CONSUMER =
new Consumer()
{
@Override
public void accept(JsonError jsonError)
{
logger.warning("Error: " + jsonError.getMessage() +
", JSON path " + jsonError.getJsonPathString());
}
};
/**
* Create a DeserializationProblemHandler that may be added to an
* ObjectMapper, and will handle unknown properties by forwarding
* the error information to the given consumer, if it is not
* null
*
* @param jsonErrorConsumer The consumer for {@link JsonError}s
* @return The problem handler
*/
private static DeserializationProblemHandler
createDeserializationProblemHandler(
Consumer super JsonError> jsonErrorConsumer)
{
return new DeserializationProblemHandler()
{
@Override
public boolean handleUnknownProperty(
DeserializationContext ctxt, JsonParser jp,
JsonDeserializer> deserializer, Object beanOrClass,
String propertyName)
throws IOException, JsonProcessingException
{
if (jsonErrorConsumer != null)
{
jsonErrorConsumer.accept(new JsonError(
"Unknown property: " + propertyName,
jp.getParsingContext(), null));
}
return super.handleUnknownProperty(
ctxt, jp, deserializer, beanOrClass, propertyName);
}
};
}
/**
* Creates a BeanDeserializerModifier that replaces the
* SettableBeanProperties in the BeanDeserializerBuilder with
* ErrorReportingSettableBeanProperty instances that forward
* information about errors when setting bean properties to the
* given consumer. (Don't ask ... )
*
* @param jsonErrorConsumer The consumer for {@link JsonError}s.
* If this is null
, then no errors will be reported.
* @return The modifier
*/
private static BeanDeserializerModifier
createErrorHandlingBeanDeserializerModifier(
Consumer super JsonError> jsonErrorConsumer)
{
return new BeanDeserializerModifier()
{
@Override
public BeanDeserializerBuilder updateBuilder(
DeserializationConfig config,
BeanDescription beanDesc,
BeanDeserializerBuilder builder)
{
Iterator propertiesIterator =
builder.getProperties();
while (propertiesIterator.hasNext())
{
SettableBeanProperty property = propertiesIterator.next();
SettableBeanProperty wrappedProperty =
new ErrorReportingSettableBeanProperty(
property, jsonErrorConsumer);
builder.addOrReplaceProperty(wrappedProperty, true);
}
return builder;
}
};
}
/**
* Returns a consumer for {@link JsonError}s that prints logging
* messages for the errors.
*
* @return The consumer
*/
public static Consumer loggingJsonErrorConsumer()
{
return LOG_JSON_ERROR_CONSUMER;
}
/**
* Perform a default configuration of the given object mapper for
* parsing glTF data
*
* @param objectMapper The object mapper
* @param jsonErrorConsumer The consumer for {@link JsonError}s. If this
* is null
, then the errors will not be handled.
*/
public static void configure(
ObjectMapper objectMapper,
Consumer super JsonError> jsonErrorConsumer)
{
// Some glTF files have single values instead of arrays,
// so accept this for compatibility reasons
objectMapper.configure(
DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
objectMapper.configure(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.addHandler(
createDeserializationProblemHandler(jsonErrorConsumer));
// Register the module that will initialize the setup context
// with the error handling bean deserializer modifier
objectMapper.registerModule(new SimpleModule()
{
/**
* Serial UID
*/
private static final long serialVersionUID = 1L;
@Override
public void setupModule(SetupContext context)
{
super.setupModule(context);
context.addBeanDeserializerModifier(
createErrorHandlingBeanDeserializerModifier(
jsonErrorConsumer));
}
});
}
/**
* Private constructor to prevent instantiation
*/
private JacksonUtils()
{
// Private constructor to prevent instantiation
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy