|
18 | 18 | import io.serverlessworkflow.impl.WorkflowModel; |
19 | 19 | import java.io.ByteArrayInputStream; |
20 | 20 | import java.io.ByteArrayOutputStream; |
| 21 | +import java.lang.reflect.Modifier; |
21 | 22 | import java.time.Instant; |
| 23 | +import java.util.ArrayList; |
22 | 24 | import java.util.Collection; |
| 25 | +import java.util.List; |
23 | 26 | import java.util.function.BiConsumer; |
24 | 27 | import java.util.function.Function; |
| 28 | +import org.slf4j.Logger; |
| 29 | +import org.slf4j.LoggerFactory; |
25 | 30 |
|
26 | 31 | public class MarshallingUtils { |
27 | 32 |
|
| 33 | + private static final Logger logger = LoggerFactory.getLogger(MarshallingUtils.class); |
| 34 | + |
28 | 35 | private MarshallingUtils() {} |
29 | 36 |
|
30 | 37 | public static byte[] writeInstant(WorkflowBufferFactory factory, Instant instant) { |
@@ -104,24 +111,75 @@ private static <T> T readValue( |
104 | 111 | * class. |
105 | 112 | * |
106 | 113 | * @param marshallers Priority Sorted collection of marshalers available on classpath |
107 | | - * @param clazz The class of the object being marshaled |
| 114 | + * @param objectClass The class of the object being marshaled |
108 | 115 | * @return The most suitable marshaler for that object class |
109 | 116 | * @throws IllegalArgumentException if no marshaler is found for that object class |
110 | 117 | */ |
111 | 118 | @SuppressWarnings({"rawtypes", "unchecked"}) |
112 | 119 | public static CustomObjectMarshaller getCustomMarshaller( |
113 | | - Collection<CustomObjectMarshaller> marshallers, Class clazz) { |
114 | | - CustomObjectMarshaller assignable = null; |
| 120 | + Collection<CustomObjectMarshaller> marshallers, Class objectClass) { |
| 121 | + List<CustomObjectMarshaller> assignables = new ArrayList<>(); |
| 122 | + int minorClassDistance = Integer.MAX_VALUE; |
| 123 | + int minorPriority = Integer.MAX_VALUE; |
115 | 124 | for (CustomObjectMarshaller marshaller : marshallers) { |
116 | | - if (marshaller.getObjectClass().equals(clazz)) { |
| 125 | + Class marshallerClass = marshaller.getObjectClass(); |
| 126 | + if (marshallerClass.equals(objectClass)) { |
117 | 127 | return marshaller; |
118 | | - } else if (marshaller.getObjectClass().isAssignableFrom(clazz) && assignable == null) { |
119 | | - assignable = marshaller; |
| 128 | + } else if (marshallerClass.isAssignableFrom(objectClass)) { |
| 129 | + int classDistance = 0; |
| 130 | + Class childClass = objectClass; |
| 131 | + boolean found = false; |
| 132 | + do { |
| 133 | + classDistance++; |
| 134 | + for (Class<?> candidate : childClass.getInterfaces()) { |
| 135 | + if (candidate.equals(marshallerClass)) { |
| 136 | + found = true; |
| 137 | + } |
| 138 | + } |
| 139 | + if (!found) { |
| 140 | + childClass = childClass.getSuperclass(); |
| 141 | + if (childClass == null) { |
| 142 | + break; |
| 143 | + } else { |
| 144 | + found = childClass.equals(marshallerClass); |
| 145 | + } |
| 146 | + } |
| 147 | + } while (!found && classDistance < minorClassDistance); |
| 148 | + if (found) { |
| 149 | + if (classDistance < minorClassDistance) { |
| 150 | + assignables.clear(); |
| 151 | + assignables.add(marshaller); |
| 152 | + minorClassDistance = classDistance; |
| 153 | + minorPriority = marshaller.priority(); |
| 154 | + } else if (classDistance == minorClassDistance |
| 155 | + && marshaller.priority() == minorPriority) { |
| 156 | + assignables.add(marshaller); |
| 157 | + } |
| 158 | + } |
120 | 159 | } |
121 | 160 | } |
122 | | - if (assignable == null) { |
123 | | - throw new IllegalArgumentException("Cannot find proper marshaler for class " + clazz); |
| 161 | + if (assignables.isEmpty()) { |
| 162 | + throw new IllegalArgumentException("Cannot find proper marshaler for class " + objectClass); |
| 163 | + } |
| 164 | + return assignables.size() == 1 ? assignables.get(0) : chooseBetweenEquals(assignables); |
| 165 | + } |
| 166 | + |
| 167 | + @SuppressWarnings("rawtypes") |
| 168 | + private static CustomObjectMarshaller chooseBetweenEquals( |
| 169 | + List<CustomObjectMarshaller> marshallers) { |
| 170 | + logger.debug("Several marshaling candidates with same priority {}", marshallers); |
| 171 | + for (CustomObjectMarshaller marshaller : marshallers) { |
| 172 | + Class marshallerClass = marshaller.getObjectClass(); |
| 173 | + if (!Modifier.isAbstract(marshallerClass.getModifiers()) |
| 174 | + && !marshallerClass.equals(Object.class)) { |
| 175 | + return marshaller; |
| 176 | + } |
| 177 | + } |
| 178 | + for (CustomObjectMarshaller marshaller : marshallers) { |
| 179 | + if (Modifier.isAbstract(marshaller.getObjectClass().getModifiers())) { |
| 180 | + return marshaller; |
| 181 | + } |
124 | 182 | } |
125 | | - return assignable; |
| 183 | + return marshallers.get(0); |
126 | 184 | } |
127 | 185 | } |
0 commit comments