blob: 9edaac21309c05b55df1f84999fd09e302fb39db [file] [log] [blame]
/*
* Copyright (c) 2010-2018 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
*/
package org.eclipse.scout.rt.jackson.dataobject;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.scout.rt.dataobject.IDataObject;
import org.eclipse.scout.rt.dataobject.IDataObjectMapper;
import org.eclipse.scout.rt.dataobject.IDoEntity;
import org.eclipse.scout.rt.dataobject.IValueFormatConstants;
import org.eclipse.scout.rt.platform.ApplicationScoped;
import org.eclipse.scout.rt.platform.BEANS;
import org.eclipse.scout.rt.platform.exception.PlatformExceptionTranslator;
import org.eclipse.scout.rt.platform.util.Assertions;
import org.eclipse.scout.rt.platform.util.LazyValue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* {@link IDataObjectMapper} implementation based on Jackson databind {@link ObjectMapper}.
*/
@ApplicationScoped
public class JacksonDataObjectMapper implements IDataObjectMapper {
private final LazyValue<ObjectMapper> m_objectMapper = new LazyValue<>(() -> createObjectMapperInstance(false));
private final LazyValue<ObjectMapper> m_rawObjectMapper = new LazyValue<>(() -> createObjectMapperInstance(true));
@Override
public <T> T readValue(InputStream inputStream, Class<T> valueType) {
Assertions.assertNotNull(inputStream, "Input stream must not be null");
try {
return m_objectMapper.get().readValue(inputStream, valueType);
}
catch (IOException e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e);
}
}
@Override
public <T> T readValue(String value, Class<T> valueType) {
if (value == null) {
return null;
}
try {
return m_objectMapper.get().readValue(value, valueType);
//return m_objectMapper.get().readerFor(valueType).withAttribute("foo", "bar").readValue(value);
}
catch (IOException e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e);
}
}
@Override
public IDataObject readValueRaw(InputStream inputStream) {
Assertions.assertNotNull(inputStream, "Input stream must not be null");
try {
return m_rawObjectMapper.get().readValue(inputStream, IDataObject.class); // use IDataObject as fixed valueType
}
catch (IOException e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e);
}
}
@Override
public IDataObject readValueRaw(String value) {
if (value == null) {
return null;
}
try {
return m_rawObjectMapper.get().readValue(value, IDataObject.class); // use IDataObject as fixed valueType
}
catch (IOException e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e);
}
}
@Override
public void writeValue(OutputStream outputStream, Object value, IMapperFeature... features) {
Assertions.assertNotNull(outputStream, "Output stream must not be null");
if (value == null) {
return;
}
try {
m_objectMapper.get().writer().withAttributes(toAttributes(features)).writeValue(outputStream, value);
}
catch (IOException e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e);
}
}
protected Map<?, ?> toAttributes(IMapperFeature... features) {
return Arrays.stream(features).collect(Collectors.toMap(IMapperFeature::getKey, IMapperFeature::getValue));
}
@Override
public String writeValue(Object value, IMapperFeature... features) {
if (value == null) {
return null;
}
try {
return m_objectMapper.get().writer().withAttributes(toAttributes(features)).writeValueAsString(value);
}
catch (JsonProcessingException e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e);
}
}
/**
* <b>Note</b> This method is exposed only for internal framework usage. It is recommended to use the
* {@link IDataObjectMapper} representation of the object mapper and not to use {@link ObjectMapper} instances
* directly in code.
*
* @deprecated Use Scout data object mapper instead, see BEANS.get(IDataObjectMapper.class)
*/
@Deprecated
public ObjectMapper getObjectMapper() {
return m_objectMapper.get();
}
/**
* Creates new {@link ObjectMapper} instance configured to be used with {@link IDoEntity}.
*/
protected ObjectMapper createObjectMapperInstance(boolean ignoreTypeAttribute) {
ObjectMapper om = new ObjectMapper();
ScoutDataObjectModule scoutDataObjectModule = BEANS.get(ScoutDataObjectModule.class).withIgnoreTypeAttribute(ignoreTypeAttribute);
prepareScoutDataModuleContext(scoutDataObjectModule.getModuleContext());
om.registerModule(scoutDataObjectModule);
om.setDateFormat(new SimpleDateFormat(IValueFormatConstants.DEFAULT_DATE_PATTERN)); // FIXME [9.0] pbz: [JSON] check if it can be moved to ScoutDataObjectModule class
om.disableDefaultTyping(); // disabled for security reasons
return om;
}
/**
* Override this method to add custom properties to {@code moduleContext}.
*/
protected void prepareScoutDataModuleContext(ScoutDataObjectModuleContext moduleContext) {
moduleContext.withDataObjectMapperClass(getClass());
}
}