Skip to content

Commit

Permalink
Merge pull request #190 from kerkhofsd/jackson2
Browse files Browse the repository at this point in the history
Fixes #189 Support Jackson2 on Alfresco 4
  • Loading branch information
tgeens committed Sep 5, 2018
2 parents 3dde1bf + 1de3160 commit c5a65fe
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Version template:
-->
# Dynamic Extensions For Alfresco Changelog

## [1.7.6] - UNRELEASED
* [#189](https://github.com/xenit-eu/dynamic-extensions-for-alfresco/issues/189) Support Json 2 on Alfresco 4


## [1.7.5] - 2018-07-04
### Fixed
* [#180](https://github.com/xenit-eu/dynamic-extensions-for-alfresco/issues/180) Use compileOnly dependencies in the gradle plugin
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.dynamicextensionsalfresco.osgi;

import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -28,14 +29,19 @@ public static <T> Collection<T> sort(Collection<T> input, DependencyMetadataProv

private static <T> void LogDebug(Collection<T> input, ArrayList<T> result) {
if (logger.isDebugEnabled()) {
logger.debug("sorting ${input.firstOrNull()}:");
Iterator<T> it = (input == null) ? null : input.iterator();
if (it == null || !it.hasNext()) {
logger.debug("sorting empty or 'null' collection");
return;
}
logger.debug("sorting {}:", it.next());
logger.debug(" input");
for (T item : input) {
logger.debug(" - $item");
logger.debug(" - {}", item);
}
logger.debug(" output");
for (T item : result) {
logger.debug(" - $item");
logger.debug(" - {}", item);
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions annotations-runtime/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
apply plugin: 'kotlin'

project.ext.jackson_version = "2.4.5"

dependencies {
compile project(':annotations')
compile project(':webscripts')
Expand All @@ -18,6 +20,9 @@ dependencies {
compile 'com.google.collections:google-collections:1.0'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

compileOnly "com.fasterxml.jackson.core:jackson-core:$jackson_version"
compileOnly "com.fasterxml.jackson.core:jackson-databind:$jackson_version"

testCompile "junit:junit:${project.ext.junitVersion}"
testCompile "org.mockito:mockito-core:${project.ext.mockitoVersion}"
testCompile "org.springframework:spring-test:${project.ext.springVersion}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed 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 com.github.dynamicextensionsalfresco.polyfill;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.Assert;

/**
* Copy of the Spring implementation to support Json 2 (com.fasterxml) in Alfresco 4.2
*
* In Alfresco 4.2, the default Spring MappingJackson2HttpMessageConverter to support Json 2 (com.fasterxml) is not yet
* available. Nevertheless, we want to support Json 2 if the {@link ObjectMapper} is available on the classpath.
*/
public class MappingJackson2HttpMessageConverter extends AbstractHttpMessageConverter<Object>
implements HttpMessageConverter<Object> {

public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");


private ObjectMapper objectMapper = new ObjectMapper();

private String jsonPrefix;

private Boolean prettyPrint;


public MappingJackson2HttpMessageConverter() {
super(new MediaType("application", "json", DEFAULT_CHARSET),
new MediaType("application", "*+json", DEFAULT_CHARSET));
}

public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
this.objectMapper = objectMapper;
configurePrettyPrint();
}

private void configurePrettyPrint() {
if (this.prettyPrint != null) {
this.objectMapper.configure(SerializationFeature.INDENT_OUTPUT, this.prettyPrint);
}
}

public ObjectMapper getObjectMapper() {
return this.objectMapper;
}

public void setJsonPrefix(String jsonPrefix) {
this.jsonPrefix = jsonPrefix;
}

public void setPrefixJson(boolean prefixJson) {
this.jsonPrefix = (prefixJson ? "{} && " : null);
}

public void setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
configurePrettyPrint();
}


@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return canRead(clazz, null, mediaType);
}

public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
JavaType javaType = getJavaType(type, contextClass);
return (this.objectMapper.canDeserialize(javaType) && canRead(mediaType));
}

@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return (this.objectMapper.canSerialize(clazz) && canWrite(mediaType));
}

@Override
protected boolean supports(Class<?> clazz) {
// should not be called, since we override canRead/Write instead
throw new UnsupportedOperationException();
}

@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {

JavaType javaType = getJavaType(clazz, null);
return readJavaType(javaType, inputMessage);
}

public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {

JavaType javaType = getJavaType(type, contextClass);
return readJavaType(javaType, inputMessage);
}

private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) {
try {
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
} catch (IOException ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
}
}


@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {

JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
JsonGenerator jsonGenerator =
this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);

// A workaround for JsonGenerators not applying serialization features
// https://github.com/FasterXML/jackson-databind/issues/12
if (this.objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
jsonGenerator.useDefaultPrettyPrinter();
}

try {
if (this.jsonPrefix != null) {
jsonGenerator.writeRaw(this.jsonPrefix);
}
this.objectMapper.writeValue(jsonGenerator, object);
} catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
}
}

protected JavaType getJavaType(Type type, Class<?> contextClass) {
return (contextClass != null) ?
this.objectMapper.getTypeFactory().constructType(type, contextClass) :
this.objectMapper.constructType(type);
}

protected JsonEncoding getJsonEncoding(MediaType contentType) {
if (contentType != null && contentType.getCharSet() != null) {
Charset charset = contentType.getCharSet();
for (JsonEncoding encoding : JsonEncoding.values()) {
if (charset.name().equals(encoding.getJavaName())) {
return encoding;
}
}
}
return JsonEncoding.UTF8;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,18 @@ public MessageConverterRegistry() {
this.messageConverters = new ArrayList<HttpMessageConverter<?>>();

if (jackson2Present) {
LOGGER.debug("Adding default converter " + MappingJackson2HttpMessageConverter.class.getName());
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
// Json 2 (com.fasterxml) is available in the classpath.
if (ClassUtils.isPresent("org.springframework.http.converter.json.MappingJackson2HttpMessageConverter",
MessageConverterRegistry.class.getClassLoader())) {
// Use the default Spring HttpMessageConverter
LOGGER.debug("Adding default converter " + MappingJackson2HttpMessageConverter.class.getName());
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
} else {
// No Spring HttpMessageConverter available for Json 2. Use our own implementation.
LOGGER.debug("Adding default converter " +
com.github.dynamicextensionsalfresco.polyfill.MappingJackson2HttpMessageConverter.class.getName());
this.messageConverters.add(new com.github.dynamicextensionsalfresco.polyfill.MappingJackson2HttpMessageConverter());
}
}
else if (jacksonPresent) {
LOGGER.debug("Adding default converter " + MappingJacksonHttpMessageConverter.class.getName());
Expand Down

0 comments on commit c5a65fe

Please sign in to comment.