blob: 8e1101cb35f492b3f9b3b44912cffb6467ded7c8 [file] [log] [blame]
/*
* Copyright (c) OSGi Alliance (2017). All Rights Reserved.
*
* 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 org.osgi.util.converter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A custom converter wraps another converter by adding rules and/or error
* handlers.
*
* @author $Id$
*/
class CustomConverterImpl implements InternalConverter {
private final InternalConverter delegate;
final Map<Type,List<ConverterFunction>> typeRules;
final List<ConverterFunction> allRules;
final List<ConverterFunction> errorHandlers;
CustomConverterImpl(InternalConverter converter,
Map<Type,List<ConverterFunction>> rules,
List<ConverterFunction> catchAllRules,
List<ConverterFunction> errHandlers) {
delegate = converter;
typeRules = rules;
allRules = catchAllRules;
errorHandlers = errHandlers;
}
@Override
public InternalConverting convert(Object obj) {
InternalConverting converting = delegate.convert(obj);
converting.setConverter(this);
return new ConvertingWrapper(obj, converting);
}
@Override
public Functioning function() {
return new FunctioningImpl(this);
}
@Override
public ConverterBuilder newConverterBuilder() {
return new ConverterBuilderImpl(this);
}
private class ConvertingWrapper implements InternalConverting {
private final InternalConverting del;
private final Object object;
private volatile Object defaultValue;
private volatile boolean hasDefault;
ConvertingWrapper(Object obj, InternalConverting c) {
object = obj;
del = c;
}
@Override
public Converting view() {
del.view();
return this;
}
@Override
public Converting defaultValue(Object defVal) {
del.defaultValue(defVal);
defaultValue = defVal;
hasDefault = true;
return this;
}
@Override
public Converting keysIgnoreCase() {
del.keysIgnoreCase();
return this;
}
@Override
public void setConverter(Converter c) {
del.setConverter(c);
}
@Override
public Converting sourceAs(Class< ? > type) {
del.sourceAs(type);
return this;
}
@Override
public Converting sourceAsBean() {
del.sourceAsBean();
return this;
}
@Override
public Converting sourceAsDTO() {
del.sourceAsDTO();
return this;
}
@Override
public Converting targetAs(Class< ? > cls) {
del.targetAs(cls);
return this;
}
@Override
public Converting targetAsBean() {
del.targetAsBean();
return this;
}
@Override
public Converting targetAsDTO() {
del.targetAsDTO();
return this;
}
@SuppressWarnings("unchecked")
@Override
public <T> T to(Class<T> cls) {
Type type = cls;
return (T) to(type);
}
@SuppressWarnings("unchecked")
@Override
public <T> T to(TypeReference<T> ref) {
return (T) to(ref.getType());
}
@SuppressWarnings("unchecked")
@Override
public Object to(Type type) {
List<ConverterFunction> tr = typeRules.get(Util.baseType(type));
if (tr == null)
tr = Collections.emptyList();
List<ConverterFunction> converters = new ArrayList<>(
tr.size() + allRules.size());
converters.addAll(tr);
converters.addAll(allRules);
try {
if (object != null) {
for (ConverterFunction cf : converters) {
try {
Object res = cf.apply(object, type);
if (res != ConverterFunction.CANNOT_HANDLE) {
return res;
}
} catch (Exception ex) {
if (hasDefault)
return defaultValue;
else
throw new ConversionException("Cannot convert "
+ object + " to " + type, ex);
}
}
}
return del.to(type);
} catch (Exception ex) {
for (ConverterFunction eh : errorHandlers) {
try {
Object handled = eh.apply(object, type);
if (handled != ConverterFunction.CANNOT_HANDLE)
return handled;
} catch (RuntimeException re) {
throw re;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// No error handler, throw the original exception
throw ex;
}
}
@Override
public String toString() {
return to(String.class);
}
}
}