All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atlasmap.core.DefaultAtlasConversionService Maven / Gradle / Ivy

/**
 * Copyright (C) 2017 Red Hat, Inc.
 * 

* 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 io.atlasmap.core; import io.atlasmap.api.AtlasConverter; import io.atlasmap.api.AtlasConversionException; import io.atlasmap.api.AtlasConversionService; import io.atlasmap.spi.AtlasConversionInfo; import io.atlasmap.spi.AtlasPrimitiveConverter; import io.atlasmap.v2.FieldType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; public class DefaultAtlasConversionService implements AtlasConversionService { private static Logger logger = LoggerFactory.getLogger(DefaultAtlasConversionService.class); private static DefaultAtlasConversionService instance = null; private Map> converters = null; private static final Set PRIMITIVE_CLASSNAMES = Collections.unmodifiableSet( new HashSet(Arrays.asList("boolean", "byte", "char", "double", "float", "int", "long", "short"))); private static final Set BOXED_PRIMITIVE_CLASSNAMES = Collections.unmodifiableSet(new HashSet( Arrays.asList("java.lang.Boolean", "java.lang.Byte", "java.lang.Character", "java.lang.Double", "java.lang.Float", "java.lang.Integer", "java.lang.Long", "java.lang.Short", "java.lang.String"))); private DefaultAtlasConversionService() { } public static DefaultAtlasConversionService getInstance() { if (instance == null) { instance = new DefaultAtlasConversionService(); instance.init(); } return instance; } public static Set listPrimitiveClassNames() { return PRIMITIVE_CLASSNAMES; } @Override @SuppressWarnings("rawtypes") public Optional findMatchingConverter(FieldType source, FieldType target) { Optional primitiveConverter = Optional.empty(); Optional customConverter = Optional.empty(); List primitiveConverters = converters.values().stream() .filter(p -> p instanceof AtlasPrimitiveConverter).map(p -> (AtlasPrimitiveConverter) p) .collect(Collectors.toList()); primitiveConverter = checkPrimitiveConverters(primitiveConverters, source, target); List customConverters = converters.values().stream() .filter(not(p -> p instanceof AtlasPrimitiveConverter)).collect(Collectors.toList()); customConverter = checkCustomConverters(customConverters, source, target); // prefer the custom converter over the primitive if (primitiveConverter.isPresent() && !customConverter.isPresent()) { return primitiveConverter; } else { return customConverter; } } @Override @SuppressWarnings("rawtypes") public Optional findMatchingConverter(String sourceClassName, String targetClassName) { // assuming only custom converters define sourceClassName / targetClassName and // must match exactly. List customConverters = converters.values().stream() .filter(not(p -> p instanceof AtlasPrimitiveConverter)).collect(Collectors.toList()); for (AtlasConverter converter : customConverters) { if (findConverterByMethodAnnotationClassName(sourceClassName, targetClassName, converter)) { return Optional.of(converter); } } return Optional.empty(); } @Override @SuppressWarnings("rawtypes") public Optional findMatchingMethod(FieldType source, FieldType target, AtlasConverter customConverter) { Method[] methods = customConverter.getClass().getMethods(); // assuming only one return Arrays.stream(methods) .filter(method -> method.isAnnotationPresent(AtlasConversionInfo.class) && (method.getAnnotation(AtlasConversionInfo.class) != null) && (method.getAnnotation(AtlasConversionInfo.class).sourceType().compareTo(source) == 0) && (method.getAnnotation(AtlasConversionInfo.class).targetType().compareTo(target) == 0)) .findFirst(); } @SuppressWarnings("rawtypes") private Optional checkCustomConverters(List customConverters, FieldType source, FieldType target) { if (source == null || target == null) { // TODO: investigate how we handle when sType -> tType (null -> something and // something -> null) return Optional.empty(); } for (AtlasConverter customConverter : customConverters) { if (findConverterByMethodAnnotationSourceType(source, target, customConverter)) { return Optional.of(customConverter); } } return Optional.empty(); } @SuppressWarnings("rawtypes") private Optional checkPrimitiveConverters(List primitiveConverters, FieldType source, FieldType target) { if (source == null || target == null) { // TODO: investigate how we handle when sType -> tType (null -> something and // something -> null) return Optional.empty(); } for (AtlasPrimitiveConverter primitiveConverter : primitiveConverters) { // get all the methods --> getAnnotations of Type AtlasConversionInfo if (findConverterByMethodAnnotationSourceType(source, target, primitiveConverter)) { return Optional.of(primitiveConverter); } } return Optional.empty(); } private boolean findConverterByMethodAnnotationSourceType(FieldType source, FieldType target, AtlasConverter customConverter) { Method[] methods = customConverter.getClass().getMethods(); return Arrays.stream(methods).map(method -> method.getAnnotation(AtlasConversionInfo.class)) .anyMatch(atlasConversionInfo -> (atlasConversionInfo != null && atlasConversionInfo.sourceType().compareTo(source) == 0 && atlasConversionInfo.targetType().compareTo(target) == 0)); } private boolean findConverterByMethodAnnotationClassName(String sourceClassName, String targetClassName, AtlasConverter customConverter) { Method[] methods = customConverter.getClass().getMethods(); return Arrays.stream(methods).map(method -> method.getAnnotation(AtlasConversionInfo.class)) .anyMatch(atlasConversionInfo -> (atlasConversionInfo != null && atlasConversionInfo.sourceClassName().equals(sourceClassName) && atlasConversionInfo.targetClassName().equals(targetClassName))); } private void init() { loadConverters(); } @SuppressWarnings("rawtypes") private void loadConverters() { ClassLoader classLoader = this.getClass().getClassLoader(); final ServiceLoader converterServiceLoader = ServiceLoader.load(AtlasConverter.class, classLoader); Map> tmp = new LinkedHashMap<>(); for (final AtlasConverter atlasConverter : converterServiceLoader) { if (logger.isDebugEnabled()) { logger.debug("Loading converter : " + atlasConverter.getClass().getCanonicalName()); } tmp.put(atlasConverter.getClass().getCanonicalName(), atlasConverter); } if (!tmp.isEmpty()) { converters = Collections.unmodifiableMap(tmp); } } private static Predicate not(Predicate predicate) { return predicate.negate(); } @Override public Object copyPrimitive(Object sourceValue) { if (sourceValue == null) { return null; } Class clazz = sourceValue.getClass(); if (clazz == null) { return clazz; } else if (boolean.class.getName().equals(clazz.getName())) { return Boolean.valueOf((boolean) sourceValue); } else if (Boolean.class.getName().equals(clazz.getName())) { return Boolean.valueOf((Boolean) sourceValue); } else if (byte.class.getName().equals(clazz.getName())) { return Byte.valueOf((byte) sourceValue); } else if (Byte.class.getName().equals(clazz.getName())) { return Byte.valueOf((Byte) sourceValue); } else if (char.class.getName().equals(clazz.getName())) { return Character.valueOf((char) sourceValue); } else if (Character.class.getName().equals(clazz.getName())) { return Character.valueOf((Character) sourceValue); } else if (double.class.getName().equals(clazz.getName())) { return Double.valueOf((double) sourceValue); } else if (Double.class.getName().equals(clazz.getName())) { return Double.valueOf((Double) sourceValue); } else if (float.class.getName().equals(clazz.getName())) { return Float.valueOf((float) sourceValue); } else if (Float.class.getName().equals(clazz.getName())) { return Float.valueOf((Float) sourceValue); } else if (int.class.getName().equals(clazz.getName())) { return Integer.valueOf((int) sourceValue); } else if (Integer.class.getName().equals(clazz.getName())) { return Integer.valueOf((Integer) sourceValue); } else if (long.class.getName().equals(clazz.getName())) { return Long.valueOf((long) sourceValue); } else if (Long.class.getName().equals(clazz.getName())) { return Long.valueOf((Long) sourceValue); } else if (short.class.getName().equals(clazz.getName())) { return Short.valueOf((short) sourceValue); } else if (Short.class.getName().equals(clazz.getName())) { return Short.valueOf((Short) sourceValue); } // can't count on java copy return sourceValue; } @Override public Object convertType(Object sourceValue, FieldType sourceType, FieldType targetType, String customClassName) throws AtlasConversionException { // TODO Auto-generated method stub return null; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Object convertType(Object sourceValue, FieldType origSourceType, FieldType targetType) throws AtlasConversionException { FieldType sourceType = null; if (origSourceType == null && sourceValue != null) { sourceType = fieldTypeFromClass(sourceValue.getClass()); } else { sourceType = FieldType.fromValue(origSourceType.value()); } if (sourceType == null && targetType == null) { throw new AtlasConversionException("AutoConversion requires sourceType and targetType be specified"); } if (sourceType.equals(targetType)) { return sourceValue; } Optional converter = findMatchingConverter(sourceType, targetType); if (!converter.isPresent()) { throw new AtlasConversionException( "Converter not found for sourceType: " + sourceType + " targetType: " + targetType); } AtlasConverter atlasConverter = converter.get(); if (isPrimitive(sourceType) && isPrimitive(targetType)) { switch (targetType) { case BOOLEAN: return ((AtlasPrimitiveConverter) atlasConverter).convertToBoolean(sourceValue); case BYTE: return ((AtlasPrimitiveConverter) atlasConverter).convertToByte(sourceValue); case CHAR: return ((AtlasPrimitiveConverter) atlasConverter).convertToCharacter(sourceValue); case DOUBLE: return ((AtlasPrimitiveConverter) atlasConverter).convertToDouble(sourceValue); case FLOAT: return ((AtlasPrimitiveConverter) atlasConverter).convertToFloat(sourceValue); case INTEGER: return ((AtlasPrimitiveConverter) atlasConverter).convertToInteger(sourceValue); case LONG: return ((AtlasPrimitiveConverter) atlasConverter).convertToLong(sourceValue); case SHORT: return ((AtlasPrimitiveConverter) atlasConverter).convertToShort(sourceValue); case STRING: return ((AtlasPrimitiveConverter) atlasConverter).convertToString(sourceValue); default: throw new AtlasConversionException( "AutoConversion is not supported for sT=" + sourceType + " tT=" + targetType); } } else { // TODO: Support non-primitive auto conversion throw new AtlasConversionException("AutoConversion of non-primitives is not supported"); } } @Override public Boolean isPrimitive(String className) { if (className == null) { return false; } if (PRIMITIVE_CLASSNAMES.contains(className)) { return true; } return false; } @Override public Boolean isPrimitive(Class clazz) { if (clazz == null) { return false; } if (PRIMITIVE_CLASSNAMES.contains(clazz.getCanonicalName())) { return true; } return false; } @Override public Boolean isPrimitive(FieldType fieldType) { if (fieldType == null) { return false; } if (Arrays .asList(FieldType.BOOLEAN, FieldType.BYTE, FieldType.CHAR, FieldType.DECIMAL, FieldType.DOUBLE, FieldType.FLOAT, FieldType.INTEGER, FieldType.LONG, FieldType.SHORT, FieldType.STRING) .contains(fieldType)) { return true; } return false; } @Override public Boolean isBoxedPrimitive(Class clazz) { if (clazz == null) { return false; } if (BOXED_PRIMITIVE_CLASSNAMES.contains(clazz.getCanonicalName())) { return true; } return false; } @Override public Class boxOrUnboxPrimitive(Class clazz) { if (clazz == null) { return clazz; } else if (boolean.class.getName().equals(clazz.getName())) { return Boolean.class; } else if (Boolean.class.getName().equals(clazz.getName())) { return boolean.class; } else if (byte.class.getName().equals(clazz.getName())) { return Byte.class; } else if (Byte.class.getName().equals(clazz.getName())) { return byte.class; } else if (char.class.getName().equals(clazz.getName())) { return Character.class; } else if (Character.class.getName().equals(clazz.getName())) { return char.class; } else if (double.class.getName().equals(clazz.getName())) { return Double.class; } else if (Double.class.getName().equals(clazz.getName())) { return double.class; } else if (float.class.getName().equals(clazz.getName())) { return Float.class; } else if (Float.class.getName().equals(clazz.getName())) { return float.class; } else if (int.class.getName().equals(clazz.getName())) { return Integer.class; } else if (Integer.class.getName().equals(clazz.getName())) { return int.class; } else if (long.class.getName().equals(clazz.getName())) { return Long.class; } else if (Long.class.getName().equals(clazz.getName())) { return long.class; } else if (short.class.getName().equals(clazz.getName())) { return Short.class; } else if (Short.class.getName().equals(clazz.getName())) { return short.class; } return clazz; } @Override public FieldType fieldTypeFromClass(Class clazz) { if (clazz == null) { return null; } return fieldTypeFromClass(clazz.getName()); } @Override public FieldType fieldTypeFromClass(String className) { if (className == null || className.isEmpty()) { return null; } switch (className) { case "boolean": return FieldType.BOOLEAN; case "java.lang.Boolean": return FieldType.BOOLEAN; case "byte": return FieldType.BYTE; case "java.lang.Byte": return FieldType.BYTE; case "char": return FieldType.CHAR; case "java.lang.Character": return FieldType.CHAR; case "double": return FieldType.DOUBLE; case "java.lang.Double": return FieldType.DOUBLE; case "float": return FieldType.FLOAT; case "java.lang.Float": return FieldType.FLOAT; case "int": return FieldType.INTEGER; case "java.lang.Integer": return FieldType.INTEGER; case "long": return FieldType.LONG; case "java.lang.Long": return FieldType.LONG; case "short": return FieldType.SHORT; case "java.lang.Short": return FieldType.SHORT; case "java.lang.String": return FieldType.STRING; case "java.time.Year": case "java.time.YearMonth": case "java.time.MonthDay": case "java.time.LocalDate": return FieldType.DATE; case "java.time.LocalTime": return FieldType.TIME; case "java.time.LocalDateTime": return FieldType.DATE_TIME; case "java.sql.Date": case "java.util.Date": case "java.time.ZonedDateTime": return FieldType.DATE_TIME_TZ; default: return FieldType.COMPLEX; } } @Override public Class classFromFieldType(FieldType fieldType) { if (fieldType == null) { return null; } switch (fieldType) { case BOOLEAN: return Boolean.class; case BYTE: return Byte.class; case CHAR: return java.lang.Character.class; case DOUBLE: return java.lang.Double.class; case FLOAT: return java.lang.Float.class; case INTEGER: return java.lang.Integer.class; case LONG: return java.lang.Long.class; case SHORT: return java.lang.Short.class; case STRING: return java.lang.String.class; case DATE: return java.time.LocalDate.class; case TIME: return java.time.LocalTime.class; case DATE_TIME: return java.time.LocalDateTime.class; case DATE_TZ: case TIME_TZ: case DATE_TIME_TZ: return java.time.ZonedDateTime.class; // TODO: need to fix the default return type for non-primitive default: return java.lang.Object.class; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy