All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.drools.core.xml.jaxb.util.JaxbUnknownAdapter Maven / Gradle / Ivy
/*
* Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* 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.drools.core.xml.jaxb.util;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.drools.core.QueryResultsImpl;
import org.drools.core.common.DisconnectedFactHandle;
import org.drools.core.runtime.rule.impl.FlatQueryResults;
import org.drools.core.xml.jaxb.util.JaxbListWrapper.JaxbWrapperType;
import org.kie.api.runtime.rule.FactHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Do not return an instance of Arrays.asList() -- that implementation is *not*
* modifiable!
*
* 7.0 plans:
* - move this at least to kie-internal
* - use JaxbObjectObjectPair instead of JaxbStringObjectPair for maps
*/
@SuppressWarnings("unchecked")
public class JaxbUnknownAdapter extends XmlAdapter {
private static final Logger logger = LoggerFactory.getLogger(JaxbUnknownAdapter.class);
private static final Object PRESENT = new Object();
@Override
public Object marshal( Object o ) throws Exception {
try {
return recursiveMarshal(o, new IdentityHashMap());
} catch( Exception e ) {
// because exceptions are always swallowed by JAXB
logger.error("Unable to marshal " + o.getClass().getName() + " instance: " + e.getMessage(), e);
throw e;
}
}
private Object recursiveMarshal( Object o, Map seenObjectsMap ) {
if( o == null ) {
return o;
}
if( seenObjectsMap.put(o, PRESENT) != null ) {
throw new UnsupportedOperationException("Serialization of recursive data structures is not supported!");
}
try {
if( o instanceof List ) {
List list = (List) o;
Object[] serializedArr = convertCollectionToSerializedArray(list, seenObjectsMap);
return new JaxbListWrapper(serializedArr, JaxbWrapperType.LIST);
} else if( o instanceof Set ) {
Set set = (Set) o;
Object[] serializedArr = convertCollectionToSerializedArray(set, seenObjectsMap);
return new JaxbListWrapper(serializedArr, JaxbWrapperType.SET);
} else if( o instanceof Map ) {
Map map = (Map) o;
List pairList = new ArrayList(map.size());
if( map == null || map.isEmpty() ) {
pairList = Collections.EMPTY_LIST;
}
for( Entry entry : map.entrySet() ) {
Object key = entry.getKey();
if( key != null && !(key instanceof String) ) {
throw new UnsupportedOperationException("Only String keys for Map structures are supported [key was a "
+ key.getClass().getName() + "]");
}
// There's already a @XmlJavaTypeAdapter(JaxbUnknownAdapter.class) anno on the JaxbStringObjectPair.value field
pairList.add(new JaxbStringObjectPair((String) key, entry.getValue()));
}
return new JaxbListWrapper(pairList.toArray(new JaxbStringObjectPair[pairList.size()]), JaxbWrapperType.MAP);
} else if( o.getClass().isArray() ) {
// convert to serializable types
int length = Array.getLength(o);
Object [] serializedArr = new Object[length];
for( int i = 0; i < length; ++i ) {
Object elem = convertObjectToSerializableVariant(Array.get(o, i), seenObjectsMap);
serializedArr[i] = elem;
}
// convert to JaxbListWrapper
JaxbListWrapper wrapper = new JaxbListWrapper(serializedArr, JaxbWrapperType.ARRAY);
Class componentType = o.getClass().getComponentType();
String componentTypeName = o.getClass().getComponentType().getCanonicalName();
if( componentTypeName == null ) {
throw new UnsupportedOperationException("Local or anonymous classes are not supported for serialization: " + componentType.getName() );
}
wrapper.setComponentType(componentTypeName);
return wrapper;
} else {
return o;
}
} finally {
seenObjectsMap.remove(o);
}
}
private Object[] convertCollectionToSerializedArray( Collection collection, Map seenObjectsMap ) {
List serializedList = new ArrayList(collection.size());
for( Object elem : collection ) {
elem = convertObjectToSerializableVariant(elem, seenObjectsMap);
serializedList.add(elem);
}
return serializedList.toArray(new Object[serializedList.size()]);
}
private Object convertObjectToSerializableVariant( Object obj, Map seenObjectsMap ) {
if( obj == null ) {
return null;
}
if( obj instanceof QueryResultsImpl ) {
obj = new FlatQueryResults((QueryResultsImpl) obj);
} else if( obj instanceof FactHandle ) {
obj = DisconnectedFactHandle.newFrom((FactHandle) obj);
} else if( !(obj instanceof JaxbListWrapper) && (obj instanceof Collection || obj instanceof Map) ) {
obj = recursiveMarshal(obj, seenObjectsMap);
}
return obj;
}
@Override
public Object unmarshal( Object o ) throws Exception {
try {
return recursiveUnmarhsal(o);
} catch( Exception e ) {
// because exceptions are always swallowed by JAXB
logger.error("Unable to *un*marshal " + o.getClass().getName() + " instance: " + e.getMessage(), e);
throw e;
}
}
public Object recursiveUnmarhsal( Object o ) throws Exception {
if( o instanceof JaxbListWrapper ) {
JaxbListWrapper wrapper = (JaxbListWrapper) o;
Object[] elements = wrapper.getElements();
int size = 0;
if( elements != null ) {
size = elements.length;
}
if( wrapper.getType() == null ) {
List list = new ArrayList(size);
return convertSerializedElementsToCollection(elements, list);
} else {
switch ( wrapper.getType() ) {
case LIST:
List list = new ArrayList(size);
return convertSerializedElementsToCollection(elements, list);
case SET:
Set set = new HashSet(size);
return convertSerializedElementsToCollection(elements, set);
case MAP:
Map map = new HashMap(size);
if( size > 0 ) {
for( Object keyValueObj : elements ) {
JaxbStringObjectPair keyValue = (JaxbStringObjectPair) keyValueObj;
Object key = keyValue.getKey();
Object value = convertSerializedObjectToObject(keyValue.getValue());
map.put(key.toString(), value);
}
}
return map;
case ARRAY:
Object [] objArr = wrapper.getElements();
int length = objArr.length;
String componentTypeName = wrapper.getComponentType();
Class realArrComponentType = null;
realArrComponentType = getClass(componentTypeName);
// create and fill array
Object realArr = Array.newInstance(realArrComponentType, objArr.length);
for( int i = 0; i < length; ++i ) {
Array.set(realArr, i, convertSerializedObjectToObject(objArr[i]));
}
return realArr;
default:
throw new IllegalArgumentException("Unknown JAXB collection wrapper type: " + wrapper.getType().toString());
}
}
} else if( o instanceof JaxbStringObjectPair[] ) {
// backwards compatibile: remove in 7.0.x
JaxbStringObjectPair[] value = (JaxbStringObjectPair[]) o;
Map r = new HashMap();
for( JaxbStringObjectPair p : value ) {
if( p.getValue() instanceof JaxbListWrapper ) {
r.put(p.getKey(), new ArrayList(Arrays.asList(((JaxbListWrapper) p.getValue()).getElements())));
} else {
r.put(p.getKey(), p.getValue());
}
}
return r;
} else {
return o;
}
}
// idea stolen from org.apache.commons.lang3.ClassUtils
private static final Map classToArrayTypeMap = new HashMap();
static {
classToArrayTypeMap.put("int", "I");
classToArrayTypeMap.put("boolean", "Z");
classToArrayTypeMap.put("float", "F");
classToArrayTypeMap.put("long", "J");
classToArrayTypeMap.put("short", "S");
classToArrayTypeMap.put("byte", "B");
classToArrayTypeMap.put("double", "D");
classToArrayTypeMap.put("char", "C");
}
private static Class getClass(String className) throws Exception {
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
ClassLoader loader = tccl == null ? JaxbUnknownAdapter.class.getClassLoader() : tccl;
try {
// String.contains() will be cheaper/faster than Map.contains()
if( className.contains(".") ) {
return Class.forName(className,true, loader);
} else {
// Thanks, org.apache.commons.lang3.ClassUtils!
String arrClassName = classToArrayTypeMap.get(className);
if( arrClassName == null ) {
throw new IllegalStateException("Unexpected class type encountered during deserialization: " + arrClassName );
}
arrClassName = "[" + arrClassName;
return Class.forName(arrClassName, true, loader).getComponentType();
}
} catch( ClassNotFoundException cnfe ) {
throw new IllegalStateException("Class '" + className + "' could not be found during deserialization: " + cnfe.getMessage(), cnfe );
}
}
private Collection convertSerializedElementsToCollection( Object[] elements, Collection collection ) throws Exception {
List list;
if( elements == null ) {
list = Collections.EMPTY_LIST;
} else {
list = new ArrayList(elements.length);
for( Object elem : elements ) {
elem = convertSerializedObjectToObject(elem);
list.add(elem);
}
}
collection.addAll(list);
return collection;
}
private Object convertSerializedObjectToObject( Object element ) throws Exception {
if( element == null ) {
return element;
}
if( element instanceof JaxbListWrapper ) {
element = unmarshal(element);
}
return element;
}
}