diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContextImpl.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContextImpl.java index 495f3194fb8..1756d487521 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContextImpl.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContextImpl.java @@ -52,7 +52,7 @@ public class PrismContextImpl implements PrismContext { private static final Trace LOGGER = TraceManager.getTrace(PrismContextImpl.class); private static boolean allowSchemalessSerialization = true; - private static boolean extraValidation = false; // TODO replace by something serious + private static boolean extraValidation = true; // TODO replace by something serious @NotNull private final SchemaRegistryImpl schemaRegistry; @NotNull private final LexicalProcessorRegistry lexicalProcessorRegistry; diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalProcessor.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalProcessor.java index cdf42a4dba2..86309bab73a 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalProcessor.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalProcessor.java @@ -29,6 +29,7 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; @@ -333,7 +334,7 @@ private PrimitiveXNode parsePrimitiveElement(final Element element) throw private static T parsePrimitiveElementValue(Element element, QName typeName, XNodeProcessorEvaluationMode mode) throws SchemaException { try { - if (ItemPath.XSD_TYPE.equals(typeName)) { + if (ItemPathType.COMPLEX_TYPE.equals(typeName)) { return (T) parsePath(element); } else if (DOMUtil.XSD_QNAME.equals(typeName)) { return (T) DOMUtil.getQNameValue(element); @@ -384,9 +385,10 @@ private static T parsePrimitiveAttrValue(Attr attr, QName typeName, XNodePro } } - private static ItemPath parsePath(Element element) { + @NotNull + private static ItemPathType parsePath(Element element) { XPathHolder holder = new XPathHolder(element); - return holder.toItemPath(); + return new ItemPathType(holder.toItemPath()); } private SchemaXNode parseSchemaElement(Element schemaElement) { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalWriter.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalWriter.java index 60a303ce465..7b7128f4cda 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalWriter.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/dom/DomLexicalWriter.java @@ -29,6 +29,7 @@ import com.evolveum.midpoint.prism.xnode.XNode; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.w3c.dom.DOMException; @@ -238,13 +239,14 @@ private void serializePrimitiveElementOrAttribute(PrimitiveXNode xprim, Eleme Element element = null; - if (typeQName.equals(ItemPath.XSD_TYPE)) { - ItemPath itemPath = (ItemPath)xprim.getValue(); - if (itemPath != null) { + if (ItemPathType.COMPLEX_TYPE.equals(typeQName)) { + //ItemPathType itemPathType = //ItemPathType.asItemPathType(xprim.getValue()); // TODO fix this hack + ItemPathType itemPathType = (ItemPathType) xprim.getValue(); + if (itemPathType != null) { if (asAttribute) { throw new UnsupportedOperationException("Serializing ItemPath as an attribute is not supported yet"); } - XPathHolder holder = new XPathHolder(itemPath); + XPathHolder holder = new XPathHolder(itemPathType.getItemPath()); element = holder.toElement(elementOrAttributeName, parentElement.getOwnerDocument()); parentElement.appendChild(element); } @@ -262,7 +264,7 @@ private void serializePrimitiveElementOrAttribute(PrimitiveXNode xprim, Eleme parentElement.appendChild(element); } - if (typeQName.equals(DOMUtil.XSD_QNAME)) { + if (DOMUtil.XSD_QNAME.equals(typeQName)) { QName value = (QName) xprim.getParsedValueWithoutRecording(DOMUtil.XSD_QNAME); value = setQNamePrefixExplicitIfNeeded(value); if (asAttribute) { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/ItemPathSerializer.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/ItemPathSerializer.java index a51a2e84d6e..26321287420 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/ItemPathSerializer.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/ItemPathSerializer.java @@ -10,14 +10,13 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; -public class ItemPathSerializer extends JsonSerializer{ +public class ItemPathSerializer extends JsonSerializer { @Override public void serialize(ItemPath value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { XPathHolder xpath = new XPathHolder(value); String path = xpath.getXPathWithDeclarations(true); -// value. jgen.writeObject(path); } @@ -25,7 +24,6 @@ public void serialize(ItemPath value, JsonGenerator jgen, SerializerProvider pro @Override public void serializeWithType(ItemPath value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { - // TODO Auto-generated method stub serialize(value, jgen, provider); } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/ItemPathTypeSerializer.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/ItemPathTypeSerializer.java new file mode 100644 index 00000000000..9c2f190f141 --- /dev/null +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/ItemPathTypeSerializer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * 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.evolveum.midpoint.prism.lex.json; + +import com.evolveum.midpoint.prism.marshaller.XPathHolder; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class ItemPathTypeSerializer extends JsonSerializer { + + @Override + public void serialize(@NotNull ItemPathType value, JsonGenerator jgen, SerializerProvider provider) throws IOException { + XPathHolder xpath = new XPathHolder(value.getItemPath()); + String path = xpath.getXPathWithDeclarations(true); + jgen.writeObject(path); + + } + + @Override + public void serializeWithType(@NotNull ItemPathType value, JsonGenerator jgen, SerializerProvider provider, + TypeSerializer typeSer) throws IOException { + serialize(value, jgen, provider); + } +} diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/JsonLexicalProcessor.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/JsonLexicalProcessor.java index 7510f53c96f..30dcecdaa61 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/JsonLexicalProcessor.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/JsonLexicalProcessor.java @@ -21,6 +21,7 @@ import com.evolveum.midpoint.prism.xnode.PrimitiveXNode; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; @@ -103,6 +104,7 @@ private Module createSerializerModule(){ module.addSerializer(QName.class, new QNameSerializer()); module.addSerializer(PolyString.class, new PolyStringSerializer()); module.addSerializer(ItemPath.class, new ItemPathSerializer()); + module.addSerializer(ItemPathType.class, new ItemPathTypeSerializer()); // module.addSerializer(Element.class, new DomElementJsonSerializer()); // module.addSerializer(JAXBElement.class, new JaxbElementSerializer()); return module; diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/XmlGregorialCalendarSerializer.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/XmlGregorianCalendarSerializer.java similarity index 92% rename from infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/XmlGregorialCalendarSerializer.java rename to infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/XmlGregorianCalendarSerializer.java index f1108d78286..da16f1fdbfe 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/XmlGregorialCalendarSerializer.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/XmlGregorianCalendarSerializer.java @@ -10,7 +10,7 @@ import com.fasterxml.jackson.databind.ext.CoreXMLSerializers.XMLGregorianCalendarSerializer; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; -public class XmlGregorialCalendarSerializer extends XMLGregorianCalendarSerializer{ +public class XmlGregorianCalendarSerializer extends XMLGregorianCalendarSerializer{ @Override public void serializeWithType(XMLGregorianCalendar value, JsonGenerator jgen, diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/YamlLexicalProcessor.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/YamlLexicalProcessor.java index 9af62ebd8a1..4244184dee5 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/YamlLexicalProcessor.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/YamlLexicalProcessor.java @@ -25,6 +25,7 @@ import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; @@ -89,10 +90,13 @@ private ObjectMapper configureMapperForSerialization(){ // mapper.configure(SerializationFeaCture.); // mapper.setSerializationInclusion(Include.NON_NULL); mapper.registerModule(createSerializerModule()); - mapper.enableDefaultTyping(DefaultTyping.NON_CONCRETE_AND_ARRAYS); - mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.EXISTING_PROPERTY); - //mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.EXTERNAL_PROPERTY); - mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY); + + mapper.disableDefaultTyping(); + +// mapper.enableDefaultTyping(DefaultTyping.NON_CONCRETE_AND_ARRAYS); +// mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.EXISTING_PROPERTY); +// //mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.EXTERNAL_PROPERTY); +// mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY); return mapper; } @@ -102,8 +106,9 @@ private Module createSerializerModule(){ module.addSerializer(QName.class, new QNameSerializer()); module.addSerializer(PolyString.class, new PolyStringSerializer()); module.addSerializer(ItemPath.class, new ItemPathSerializer()); + module.addSerializer(ItemPathType.class, new ItemPathTypeSerializer()); // module.addSerializer(JAXBElement.class, new JaxbElementSerializer()); - module.addSerializer(XMLGregorianCalendar.class, new XmlGregorialCalendarSerializer()); + module.addSerializer(XMLGregorianCalendar.class, new XmlGregorianCalendarSerializer()); module.addSerializer(Element.class, new DomElementSerializer()); return module; } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/yaml/MidpointYAMLFactory.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/yaml/MidpointYAMLFactory.java index f0af223b299..a92bda4208a 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/yaml/MidpointYAMLFactory.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/lex/json/yaml/MidpointYAMLFactory.java @@ -13,6 +13,8 @@ public class MidpointYAMLFactory extends YAMLFactory { + + @Override protected MidpointYAMLGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException { int feats = _yamlGeneratorFeatures; diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanMarshaller.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanMarshaller.java index a849e9b1b34..1544f5c5813 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanMarshaller.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanMarshaller.java @@ -31,14 +31,13 @@ import com.evolveum.prism.xml.ns._public.types_3.*; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlType; import javax.xml.namespace.QName; import java.lang.reflect.*; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; +import java.util.*; public class BeanMarshaller { @@ -46,113 +45,64 @@ public class BeanMarshaller { public static final String DEFAULT_PLACEHOLDER = "##default"; - private PrismBeanInspector inspector; - + @NotNull private final PrismBeanInspector inspector; @NotNull private final PrismContext prismContext; + @NotNull private final Map specialMarshallers = new HashMap<>(); - public BeanMarshaller(@NotNull PrismContext prismContext, PrismBeanInspector inspector) { - this.prismContext = prismContext; - this.inspector = inspector; + @FunctionalInterface + private interface Marshaller { + XNode marshal(Object bean, SerializationContext sc) throws SchemaException; } - @NotNull - public PrismContext getPrismContext() { - return prismContext; + private void createSpecialMarshallerMap() { + specialMarshallers.put(XmlAsStringType.class, this::marshalXmlAsStringType); + specialMarshallers.put(SchemaDefinitionType.class, this::marshalSchemaDefinition); + specialMarshallers.put(ProtectedByteArrayType.class, this::marshalProtectedDataType); + specialMarshallers.put(ProtectedStringType.class, this::marshalProtectedDataType); + specialMarshallers.put(ItemPathType.class, this::marshalItemPathType); + specialMarshallers.put(RawType.class, this::marshalRawType); +// add(PolyString.class, this::unmarshalPolyStringFromPrimitive, this::unmarshalPolyStringFromMap); +// add(PolyStringType.class, this::unmarshalPolyStringFromPrimitive, this::unmarshalPolyStringFromMap); } - private SchemaRegistry getSchemaRegistry() { - return prismContext.getSchemaRegistry(); + public BeanMarshaller(@NotNull PrismContext prismContext, @NotNull PrismBeanInspector inspector) { + this.prismContext = prismContext; + this.inspector = inspector; + createSpecialMarshallerMap(); } - public boolean canProcess(QName typeName) { - return getSchemaRegistry().determineCompileTimeClass(typeName) != null; - } - - public boolean canProcess(@NotNull Class clazz) { - return RawType.class.equals(clazz) || clazz.getAnnotation(XmlType.class) != null; - } - - public QName determineTypeForClass(Class clazz) { - return inspector.determineTypeForClass(clazz); - } - - private MapXNode marshalSearchFilterType(SearchFilterType value) throws SchemaException { - if (value == null) { - return null; - } - return value.serializeToXNode(); + @Nullable + public XNode marshall(@Nullable T bean) throws SchemaException { + return marshall(bean, null); } - private Type getTypeArgument(Type origType, String desc) { - if (!(origType instanceof ParameterizedType)) { - throw new IllegalArgumentException("No a parametrized type "+desc); - } - ParameterizedType parametrizedType = (ParameterizedType)origType; - Type[] actualTypeArguments = parametrizedType.getActualTypeArguments(); - if (actualTypeArguments == null || actualTypeArguments.length == 0) { - throw new IllegalArgumentException("No type arguments for getter "+desc); + @Nullable + public XNode marshall(@Nullable T bean, @Nullable SerializationContext ctx) throws SchemaException { + if (bean == null) { + return null; } - if (actualTypeArguments.length > 1) { - throw new IllegalArgumentException("Too many type arguments for getter for "+desc); + Marshaller marshaller = specialMarshallers.get(bean.getClass()); + if (marshaller != null) { + return marshaller.marshal(bean, ctx); + } else if (bean instanceof Containerable) { + // we shouldn't get here but ... + return prismContext.xnodeSerializer().serializeRealValue(bean, new QName("dummy")).getSubnode(); + } else if (bean instanceof Enum) { + return marshalEnum((Enum) bean, ctx); + } else if (bean.getClass().getAnnotation(XmlType.class) != null) { + return marshalXmlType(bean, ctx); + } else { + return marshalToPrimitive(bean, ctx); } - return actualTypeArguments[0]; } - - // TODO hacked, for now -// private String findEnumFieldValue(Class classType, Object bean){ -// String name = bean.toString(); -// for (Field field: classType.getDeclaredFields()) { -// XmlEnumValue xmlEnumValue = field.getAnnotation(XmlEnumValue.class); -// if (xmlEnumValue != null && field.getName().equals(name)) { -// return xmlEnumValue.value(); -// } -// } -// return null; -// } - - - public XNode marshall(T bean) throws SchemaException { - return marshall(bean, null); + private XNode marshalToPrimitive(Object bean, SerializationContext ctx) { + return createPrimitiveXNode(bean, null, false); } - public XNode marshall(T bean, SerializationContext ctx) throws SchemaException { - if (bean == null) { - return null; - } - if (bean instanceof SchemaDefinitionType) { - return marshalSchemaDefinition((SchemaDefinitionType) bean); - } else if (bean instanceof ProtectedDataType) { - MapXNode xProtected = marshalProtectedDataType((ProtectedDataType) bean); - return xProtected; - } else if (bean instanceof ItemPathType){ - return marshalItemPathType((ItemPathType) bean); - } else if (bean instanceof RawType) { - return marshalRawValue((RawType) bean); - } else if (bean instanceof XmlAsStringType) { - return marshalXmlAsStringType((XmlAsStringType) bean); - } else if (prismContext != null && prismContext.getSchemaRegistry().determineDefinitionFromClass(bean.getClass()) != null){ - // TODO change to marshalItemContent - return ((PrismContextImpl) prismContext).getPrismMarshaller().marshalItemAsRoot(((Objectable)bean).asPrismObject(), - null, null, ctx).getSubnode(); - } - // Note: SearchFilterType is treated below + private XNode marshalXmlType(Object bean, SerializationContext ctx) throws SchemaException { - Class beanClass = bean.getClass(); - - if (beanClass == String.class) { - return createPrimitiveXNode((String)bean, DOMUtil.XSD_STRING, false); - } - - //check for enums - if (beanClass.isEnum()){ - String enumValue = inspector.findEnumFieldValue(beanClass, bean.toString()); - if (StringUtils.isEmpty(enumValue)){ - enumValue = bean.toString(); - } - QName fieldTypeName = inspector.findFieldTypeName(null, beanClass, DEFAULT_PLACEHOLDER); - return createPrimitiveXNode(enumValue, fieldTypeName, false); - } + Class beanClass = bean.getClass(); MapXNode xmap; if (bean instanceof SearchFilterType) { @@ -165,11 +115,6 @@ public XNode marshall(T bean, SerializationContext ctx) throws SchemaExcepti xmap = new MapXNode(); } - XmlType xmlType = beanClass.getAnnotation(XmlType.class); - if (xmlType == null) { - throw new IllegalArgumentException("Cannot marshall "+beanClass+" it does not have @XmlType annotation"); - } - String namespace = inspector.determineNamespace(beanClass); if (namespace == null) { throw new IllegalArgumentException("Cannot determine namespace of "+beanClass); @@ -197,15 +142,15 @@ public XNode marshall(T bean, SerializationContext ctx) throws SchemaExcepti boolean isAttribute = inspector.isAttribute(field, getter); if (getterResult instanceof Collection) { - Collection col = (Collection)getterResult; + Collection col = (Collection) getterResult; if (col.isEmpty()) { continue; } Iterator i = col.iterator(); - if (i == null) { - // huh?!? .. but it really happens - throw new IllegalArgumentException("Iterator of collection returned from "+getter+" is null"); - } +// if (i == null) { +// // huh?!? .. but it really happens +// throw new IllegalArgumentException("Iterator of collection returned from "+getter+" is null"); +// } Object getterResultValue = i.next(); if (getterResultValue == null) { continue; @@ -276,9 +221,20 @@ public XNode marshall(T bean, SerializationContext ctx) throws SchemaExcepti return xmap; } - private XNode marshalXmlAsStringType(XmlAsStringType bean) { + private XNode marshalEnum(Enum bean, SerializationContext ctx) { + Class beanClass = bean.getClass(); + String enumValue = inspector.findEnumFieldValue(beanClass, bean.toString()); + if (StringUtils.isEmpty(enumValue)){ + enumValue = bean.toString(); + } + QName fieldTypeName = inspector.findFieldTypeName(null, beanClass, DEFAULT_PLACEHOLDER); + return createPrimitiveXNode(enumValue, fieldTypeName, false); + + } + + private XNode marshalXmlAsStringType(Object bean, SerializationContext sc) { PrimitiveXNode xprim = new PrimitiveXNode<>(); - xprim.setValue(bean.getContentAsString(), DOMUtil.XSD_STRING); + xprim.setValue(((XmlAsStringType) bean).getContentAsString(), DOMUtil.XSD_STRING); return xprim; } @@ -370,7 +326,7 @@ private void setExplicitTypeDeclarationIfNeeded(Method getter, Object getterResu if (Collection.class.isAssignableFrom(getterReturnType)){ Type genericReturnType = getter.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ - Type actualType = getTypeArgument(genericReturnType, "explicit type declaration"); + Type actualType = inspector.getTypeArgument(genericReturnType, "explicit type declaration"); if (actualType instanceof Class){ getterType = (Class) actualType; @@ -391,16 +347,15 @@ private XNode marshallValue(T value, QName fieldTypeName, boolean isAttribut if (value == null) { return null; } - if (canProcess(value.getClass())) { - // This must be a bean - return marshall(value, ctx); - } else { - // primitive value + if (isAttribute) { + // hoping the value fits into primitive! return createPrimitiveXNode(value, fieldTypeName, isAttribute); + } else { + return marshall(value, ctx); } } - private PrimitiveXNode createPrimitiveXNode(T value, QName fieldTypeName, boolean isAttribute){ + private PrimitiveXNode createPrimitiveXNode(T value, QName fieldTypeName, boolean isAttribute) { PrimitiveXNode xprim = new PrimitiveXNode(); xprim.setValue(value, fieldTypeName); xprim.setAttribute(isAttribute); @@ -411,20 +366,21 @@ private PrimitiveXNode createPrimitiveXNode(T val, QName type) { return createPrimitiveXNode(val, type, false); } - private XNode marshalRawValue(RawType value) throws SchemaException { - return value.serializeToXNode(); + private XNode marshalRawType(Object value, SerializationContext sc) throws SchemaException { + return ((RawType) value).serializeToXNode(); } - private XNode marshalItemPathType(ItemPathType itemPath) { - PrimitiveXNode xprim = new PrimitiveXNode(); - if (itemPath != null){ - ItemPath path = itemPath.getItemPath(); - xprim.setValue(path, ItemPathType.COMPLEX_TYPE); + private XNode marshalItemPathType(Object o, SerializationContext sc) { + ItemPathType itemPath = (ItemPathType) o; + PrimitiveXNode xprim = new PrimitiveXNode<>(); + if (itemPath != null) { + xprim.setValue(itemPath, ItemPathType.COMPLEX_TYPE); } return xprim; } - private XNode marshalSchemaDefinition(SchemaDefinitionType schemaDefinitionType) { + private XNode marshalSchemaDefinition(Object o, SerializationContext ctx) { + SchemaDefinitionType schemaDefinitionType = (SchemaDefinitionType) o; SchemaXNode xschema = new SchemaXNode(); xschema.setSchemaElement(schemaDefinitionType.getSchema()); MapXNode xmap = new MapXNode(); @@ -433,7 +389,8 @@ private XNode marshalSchemaDefinition(SchemaDefinitionType schemaDefinitionType) } // TODO create more appropriate interface to be able to simply serialize ProtectedStringType instances - public MapXNode marshalProtectedDataType(ProtectedDataType protectedType) throws SchemaException { + public MapXNode marshalProtectedDataType(Object o, SerializationContext sc) throws SchemaException { + ProtectedDataType protectedType = (ProtectedDataType) o; MapXNode xmap = new MapXNode(); if (protectedType.getEncryptedDataType() != null) { EncryptedDataType encryptedDataType = protectedType.getEncryptedDataType(); @@ -447,5 +404,52 @@ public MapXNode marshalProtectedDataType(ProtectedDataType protectedType) // TODO: clearValue return xmap; } + + + //region Specific marshallers ============================================================== + private MapXNode marshalSearchFilterType(SearchFilterType value) throws SchemaException { + if (value == null) { + return null; + } + return value.serializeToXNode(); + } + + //endregion + + @NotNull + public PrismContext getPrismContext() { + return prismContext; + } + + private SchemaRegistry getSchemaRegistry() { + return prismContext.getSchemaRegistry(); + } + + public boolean canProcess(QName typeName) { + Class clazz = getSchemaRegistry().determineClassForType(typeName); + return clazz != null && canProcess(clazz); + } + + public boolean canProcess(@NotNull Class clazz) { + return !Containerable.class.isAssignableFrom(clazz) && + (RawType.class.equals(clazz) || clazz.getAnnotation(XmlType.class) != null || XsdTypeMapper.getTypeFromClass(clazz) != null); + } + + public QName determineTypeForClass(Class clazz) { + return inspector.determineTypeForClass(clazz); + } + } - \ No newline at end of file + + +// TODO hacked, for now +// private String findEnumFieldValue(Class classType, Object bean){ +// String name = bean.toString(); +// for (Field field: classType.getDeclaredFields()) { +// XmlEnumValue xmlEnumValue = field.getAnnotation(XmlEnumValue.class); +// if (xmlEnumValue != null && field.getName().equals(name)) { +// return xmlEnumValue.value(); +// } +// } +// return null; +// } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanUnmarshaller.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanUnmarshaller.java index 2e43c38365b..9a07a66cf07 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanUnmarshaller.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/BeanUnmarshaller.java @@ -24,7 +24,6 @@ import com.evolveum.midpoint.prism.xml.XsdTypeMapper; import com.evolveum.midpoint.prism.xnode.*; import com.evolveum.midpoint.util.DOMUtil; -import com.evolveum.midpoint.util.Handler; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SystemException; @@ -33,14 +32,16 @@ import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import com.evolveum.prism.xml.ns._public.types_3.*; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.w3c.dom.Element; import javax.xml.bind.JAXBElement; -import javax.xml.bind.annotation.XmlType; import javax.xml.namespace.QName; +import java.io.UnsupportedEncodingException; import java.lang.reflect.*; import java.util.*; import java.util.Map.Entry; @@ -56,75 +57,131 @@ public class BeanUnmarshaller { @NotNull private final PrismBeanInspector inspector; @NotNull private final PrismContext prismContext; + @NotNull private final Map specialPrimitiveUnmarshallers = new HashMap<>(); + @NotNull private final Map specialMapUnmarshallers = new HashMap<>(); public BeanUnmarshaller(@NotNull PrismContext prismContext, @NotNull PrismBeanInspector inspector) { this.prismContext = prismContext; this.inspector = inspector; + createSpecialUnmarshallerMaps(); } - @NotNull - public PrismContext getPrismContext() { - return prismContext; + @FunctionalInterface + private interface PrimitiveUnmarshaller { + T unmarshal(PrimitiveXNode node, Class beanClass, ParsingContext pc) throws SchemaException; } - @NotNull - private SchemaRegistry getSchemaRegistry() { - return prismContext.getSchemaRegistry(); + @FunctionalInterface + private interface MapUnmarshaller { + T unmarshal(MapXNode node, Class beanClass, ParsingContext pc) throws SchemaException; } + private void add(Class beanClass, PrimitiveUnmarshaller primitive, MapUnmarshaller map) { + specialPrimitiveUnmarshallers.put(beanClass, primitive); + specialMapUnmarshallers.put(beanClass, map); + } + + private void createSpecialUnmarshallerMaps() { + add(XmlAsStringType.class, this::unmarshalXmlAsStringFromPrimitive, this::unmarshalXmlAsStringFromMap); + add(RawType.class, this::unmarshalRawType, this::unmarshalRawType); + add(PolyString.class, this::unmarshalPolyStringFromPrimitive, this::unmarshalPolyStringFromMap); + add(PolyStringType.class, this::unmarshalPolyStringFromPrimitive, this::unmarshalPolyStringFromMap); + add(ItemPathType.class, this::unmarshalItemPath, this::notSupported); + add(ProtectedStringType.class, this::unmarshalProtectedString, this::unmarshalProtectedString); + add(ProtectedByteArrayType.class, this::unmarshalProtectedByteArray, this::unmarshalProtectedByteArray); + add(SchemaDefinitionType.class, this::notSupported, this::unmarshalSchemaDefinitionType); + } + //region Main entry ========================================================================== + /* + * Preconditions: + * 1. typeName is processable by unmarshaller - i.e. it corresponds to simple or complex type NOT of containerable character + */ + + @NotNull T unmarshal(@NotNull XNode xnode, @NotNull QName typeQName, @NotNull ParsingContext pc) throws SchemaException { - Class classType = getSchemaRegistry().determineCompileTimeClass(typeQName); // TODO use correct method! + Class classType = getSchemaRegistry().determineClassForType(typeQName); // TODO use correct method! return unmarshal(xnode, classType, pc); } + @NotNull T unmarshal(@NotNull XNode xnode, @NotNull Class beanClass, @NotNull ParsingContext pc) throws SchemaException { + T value = unmarshalInternal(xnode, beanClass, pc); + if (PrismContextImpl.isExtraValidation() && value != null) { + Class requested = ClassUtils.primitiveToWrapper(beanClass); + Class actual = ClassUtils.primitiveToWrapper(value.getClass()); + if (!requested.isAssignableFrom(actual)) { + throw new AssertionError("Postcondition fail: unmarshal returned a value of " + value + " (" + + actual + ") which is not of requested type (" + requested + ")"); + } + } + return value; + } + private T unmarshalInternal(@NotNull XNode xnode, @NotNull Class beanClass, @NotNull ParsingContext pc) throws SchemaException { + if (xnode instanceof RootXNode) { + XNode subnode = ((RootXNode) xnode).getSubnode(); + if (subnode == null) { + throw new IllegalStateException("Couldn't parse " + beanClass + " from a root node with a null content: " + xnode.debugDump()); + } else { + return unmarshal(subnode, beanClass, pc); + } + } else if (!(xnode instanceof MapXNode) && !(xnode instanceof PrimitiveXNode)) { + throw new IllegalStateException("Couldn't parse " + beanClass + " from non-map/non-primitive node: " + xnode.debugDump()); + } + // only maps and primitives after this point if (xnode instanceof PrimitiveXNode) { - return unmarshalFromPrimitive((PrimitiveXNode) xnode, beanClass, pc); - } else if (xnode instanceof MapXNode) { - return unmarshalFromMap((MapXNode) xnode, beanClass, pc); - } else if (xnode instanceof RootXNode) { - return unmarshal(((RootXNode) xnode).getSubnode(), beanClass, pc); + PrimitiveXNode prim = (PrimitiveXNode) xnode; + if (XmlTypeConverter.canConvert(beanClass)) { + QName xsdType = XsdTypeMapper.toXsdType(beanClass); + Object parsedValue = prim.getParsedValue(xsdType); + return postConvertUnmarshal(parsedValue, pc); + } else if (beanClass.isEnum()) { + return unmarshalEnumFromPrimitive(prim, beanClass, pc); + } + @SuppressWarnings("unchecked") + PrimitiveUnmarshaller unmarshaller = specialPrimitiveUnmarshallers.get(beanClass); + if (unmarshaller != null) { + return unmarshaller.unmarshal(prim, beanClass, pc); + } else if (prim.isEmpty()) { + // Special case. Just return empty object + try { + return beanClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new SystemException("Cannot instantiate "+beanClass+": "+e.getMessage(), e); + } + } else { + throw new SchemaException("Cannot convert primitive value to bean of type " + beanClass); + } } else { - throw new IllegalStateException("Unexpected xnode " + xnode + ". Could not unmarshal value"); + @SuppressWarnings("unchecked") + MapUnmarshaller unmarshaller = specialMapUnmarshallers.get(beanClass); + if (unmarshaller != null) { + return unmarshaller.unmarshal((MapXNode) xnode, beanClass, pc); + } + return unmarshalFromMap((MapXNode) xnode, beanClass, pc); } } + public boolean canProcess(QName typeName) { + return ((PrismContextImpl) getPrismContext()).getBeanMarshaller().canProcess(typeName); + } + + public boolean canProcess(Class clazz) { + return ((PrismContextImpl) getPrismContext()).getBeanMarshaller().canProcess(clazz); + } + //endregion + + private T unmarshalFromMap(@NotNull MapXNode xmap, @NotNull Class beanClass, @NotNull ParsingContext pc) throws SchemaException { - if (PolyStringType.class.equals(beanClass)) { - return (T) PolyStringType.unmarshal(xmap); - } else if (ProtectedStringType.class.equals(beanClass)) { - return (T) ProtectedStringType.unmarshal(xmap); - ProtectedStringType protectedType = new ProtectedStringType(); - XNodeProcessorUtil.parseProtectedType(protectedType, xmap, prismContext, pc); - return (T) protectedType; - } else if (ProtectedByteArrayType.class.equals(beanClass)) { - ProtectedByteArrayType protectedType = new ProtectedByteArrayType(); - XNodeProcessorUtil.parseProtectedType(protectedType, xmap, prismContext, pc); - return (T) protectedType; - } else if (SchemaDefinitionType.class.equals(beanClass)) { - SchemaDefinitionType schemaDefType = unmarshalSchemaDefinitionType(xmap); - return (T) schemaDefType; - } else if (prismContext.getSchemaRegistry().determineDefinitionFromClass(beanClass) != null) { - PrismObjectDefinition def = prismContext.getSchemaRegistry().determineDefinitionFromClass(beanClass); - return (T) ((PrismContextImpl) prismContext).getPrismUnmarshaller().parseObject(xmap, def, pc).asObjectable(); - } else if (XmlAsStringType.class.equals(beanClass)) { - // reading a string represented a XML-style content - // used e.g. when reading report templates (embedded XML) - // A necessary condition: there may be only one map entry. - if (xmap.size() > 1) { - throw new SchemaException("Map with more than one item cannot be parsed as a string: " + xmap); - } else if (xmap.isEmpty()) { - return (T) new XmlAsStringType(); - } else { - Entry entry = xmap.entrySet().iterator().next(); - DomLexicalProcessor domParser = ((PrismContextImpl) prismContext).getParserDom(); - String value = domParser.write(entry.getValue(), entry.getKey(), null); - return (T) new XmlAsStringType(value); - } + + if (Containerable.class.isAssignableFrom(beanClass)) { + // This could have come from inside + PrismValue value = prismContext.parserFor(xmap.toRootXNode()).type(beanClass).parseItemValue(); + return (T) value.getRealValue(); + //throw new IllegalArgumentException("Couldn't process Containerable: " + beanClass + " from " + xmap.debugDump()); } else if (SearchFilterType.class.isAssignableFrom(beanClass)) { T bean = (T) unmarshalSearchFilterType(xmap, (Class) beanClass, pc); // TODO fix this BRUTAL HACK - it is here because of c:ConditionalSearchFilterType @@ -141,302 +198,379 @@ private T unmarshalFromMap(@NotNull MapXNode xmap, @NotNull Class beanCla } private T unmarshalFromMapToBean(@NotNull T bean, @NotNull MapXNode xmap, @Nullable Collection keysToParse, @NotNull ParsingContext pc) throws SchemaException { + @SuppressWarnings("unchecked") Class beanClass = (Class) bean.getClass(); - - for (Entry entry: xmap.entrySet()) { + for (Entry entry : xmap.entrySet()) { QName key = entry.getKey(); - if (keysToParse != null && !keysToParse.contains(key.getLocalPart())) { - continue; - } - XNode xsubnode = entry.getValue(); - String propName = key.getLocalPart(); - Field field = inspector.findPropertyField(beanClass, propName); + if (keysToParse != null && !keysToParse.contains(key.getLocalPart())) { + continue; + } + unmarshalMapEntry(bean, beanClass, entry.getKey(), entry.getValue(), xmap, pc); + } + return bean; + } + + private void unmarshalMapEntry(@NotNull T bean, @NotNull Class beanClass, + @NotNull QName key, @NotNull XNode node, @NotNull MapXNode containingMap, @NotNull ParsingContext pc) throws SchemaException { + + final String propName = key.getLocalPart(); + + // this code is just to keep this method reasonably short + PropertyAccessMechanism mechanism = new PropertyAccessMechanism(); + if (!mechanism.compute(bean, beanClass, propName, key, node, pc)) { + return; + } + + final String actualPropertyName = mechanism.actualPropertyName; + final boolean storeAsRawType = mechanism.storeAsRawType; + + final Method getter = mechanism.getter; + final Method setter = mechanism.setter; + Class paramType = mechanism.paramType; + final boolean wrapInJaxbElement = mechanism.wrapInJaxbElement; + + if (Element.class.isAssignableFrom(paramType)) { + throw new IllegalArgumentException("DOM not supported in field "+actualPropertyName+" in "+beanClass); + } + + //check for subclasses??? + if (!storeAsRawType && node.getTypeQName() != null) { + Class explicitParamType = getSchemaRegistry().determineClassForType(node.getTypeQName()); + if (explicitParamType != null) { + paramType = explicitParamType; + } + } + + if (!(node instanceof ListXNode) && Object.class.equals(paramType) && !storeAsRawType) { + throw new IllegalArgumentException("Object property (without @Raw) not supported in field "+actualPropertyName+" in "+beanClass); + } + + String paramNamespace = inspector.determineNamespace(paramType); + + boolean problem = false; + Object propValue = null; + Collection propValues = null; + if (node instanceof ListXNode) { + ListXNode xlist = (ListXNode)node; + if (setter != null) { + try { + propValue = convertSinglePropValue(node, actualPropertyName, paramType, storeAsRawType, beanClass, paramNamespace, pc); + } catch (SchemaException e) { + problem = processSchemaException(e, node, pc); + } + } else { + // No setter, we have to use collection getter + propValues = new ArrayList<>(xlist.size()); + for (XNode xsubsubnode: xlist) { + try { + propValues.add(convertSinglePropValue(xsubsubnode, actualPropertyName, paramType, storeAsRawType, beanClass, paramNamespace, pc)); + } catch (SchemaException e) { + problem = processSchemaException(e, xsubsubnode, pc); + } + } + } + } else { + try { + propValue = convertSinglePropValue(node, actualPropertyName, paramType, storeAsRawType, beanClass, paramNamespace, pc); + } catch (SchemaException e) { + problem = processSchemaException(e, node, pc); + } + } + + if (setter != null) { + Object value = null; + try { + value = prepareValueToBeStored(propValue, wrapInJaxbElement, mechanism.objectFactory, mechanism.elementFactoryMethod, propName, beanClass, pc); + setter.invoke(bean, value); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new SystemException("Cannot invoke setter "+setter+" on bean of type "+beanClass+": "+e.getMessage(), e); + } + } else if (getter != null) { + Object getterReturn; + Collection col; + try { + getterReturn = getter.invoke(bean); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new SystemException("Cannot invoke getter "+getter+" on bean of type "+beanClass+": "+e.getMessage(), e); + } + try { + col = (Collection)getterReturn; + } catch (ClassCastException e) { + throw new SystemException("Getter "+getter+" on bean of type "+beanClass+" returned "+getterReturn+" instead of collection"); + } + if (propValue != null) { + col.add(prepareValueToBeStored(propValue, wrapInJaxbElement, mechanism.objectFactory, mechanism.elementFactoryMethod, propName, beanClass, pc)); + } else if (propValues != null) { + for (Object propVal: propValues) { + col.add(prepareValueToBeStored(propVal, wrapInJaxbElement, mechanism.objectFactory, mechanism.elementFactoryMethod, propName, beanClass, pc)); + } + } else if (!problem) { + throw new IllegalStateException("Strange. Multival property "+propName+" in "+beanClass+" produced null values list, parsed from "+containingMap); + } + checkJaxbElementConsistence(col, pc); + } else { + throw new IllegalStateException("Uh? No setter nor getter."); + } + } + + private class PropertyAccessMechanism { + + Class beanClass; + + // phase1 + String actualPropertyName; // This is the name of property we will really use. (Considering e.g. substitutions.) + boolean storeAsRawType; // Whether the data will be stored as RawType. + Object objectFactory; // JAXB object factory instance (e.g. xxxx.common-3.ObjectFactory). + Method elementFactoryMethod; // Method in object factory that creates a given JAXB element (e.g. createAsIs(value)) + + // phase2 + Method getter, setter; // Getter or setter that will be used to put a value (getter in case of collections) + Class paramType; // Actual parameter type; unwrapped: Collection -> X, JAXBElement -> X + boolean wrapInJaxbElement; // If the paramType contained JAXBElement, i.e. if the value should be wrapped into it before using + + // returns true if the processing is to be continued; + // false in case of using alternative way of unmarshalling (e.g. use of "any" method), or in case of error (in COMPAT mode) + private boolean compute(T bean, Class beanClass, String propName, QName key, XNode node, ParsingContext pc) + throws SchemaException { + + this.beanClass = beanClass; + + // phase1 + if (!computeActualPropertyName(bean, propName, key, node, pc)) { + return false; + } + // phase2 + return computeGetterAndSetter(propName, pc); + } + + // computes actualPropertyName + storeAsRawType + // if necessary, fills-in also objectFactory + elementFactoryMethod + private boolean computeActualPropertyName(T bean, String propName, QName key, XNode node, ParsingContext pc) + throws SchemaException { + Field propertyField = inspector.findPropertyField(beanClass, propName); Method propertyGetter = null; - if (field == null) { + if (propertyField == null) { propertyGetter = inspector.findPropertyGetter(beanClass, propName); } - Method elementMethod = null; - Object objectFactory = null; - if (field == null && propertyGetter == null) { + elementFactoryMethod = null; + objectFactory = null; + if (propertyField == null && propertyGetter == null) { // We have to try to find a more generic field, such as xsd:any or substitution element // check for global element definition first - Class objectFactoryClass = inspector.getObjectFactoryClass(beanClass.getPackage()); - objectFactory = instantiateObjectFactory(objectFactoryClass); - elementMethod = inspector.findElementMethodInObjectFactory(objectFactoryClass, propName); - if (elementMethod == null) { - // Check for "any" method - elementMethod = inspector.findAnyMethod(beanClass); - if (elementMethod == null) { - String m = "No field "+propName+" in class "+beanClass+" (and no element method in object factory too)"; - if (pc.isCompat()) { - pc.warn(LOGGER, m); - continue; + elementFactoryMethod = findElementFactoryMethod(propName); + if (elementFactoryMethod != null) { + // great - global element found, let's look up the field + propertyField = inspector.lookupSubstitution(beanClass, elementFactoryMethod); + if (propertyField == null) { + propertyField = inspector.findAnyField(beanClass); // Check for "any" field + if (propertyField != null) { + unmarshalToAnyUsingField(bean, propertyField, key, node, pc); } else { - throw new SchemaException(m); + unmarshalToAnyUsingGetterIfExists(bean, key, node, pc, propName); } + return false; } - unmarshallToAny(bean, elementMethod, key, xsubnode, pc); - continue; - - } - field = inspector.lookupSubstitution(beanClass, elementMethod); - if (field == null) { - // Check for "any" field - field = inspector.findAnyField(beanClass); - if (field == null) { - elementMethod = inspector.findAnyMethod(beanClass); - if (elementMethod == null) { - String m = "No field "+propName+" in class "+beanClass+" (and no element method in object factory too)"; - if (pc.isCompat()) { - pc.warn(LOGGER, m); - continue; - } else { - throw new SchemaException(m); - } - } - unmarshallToAny(bean, elementMethod, key, xsubnode, pc); - continue; -// throw new SchemaException("No field "+propName+" in class "+beanClass+" (no suitable substitution and no 'any' field)"); - } - unmarshallToAny(bean, field, key, xsubnode, pc); - continue; + } else { + unmarshalToAnyUsingGetterIfExists(bean, key, node, pc, propName); // e.g. "getAny()" + return false; } } - boolean storeAsRawType; - if (elementMethod != null) { - storeAsRawType = elementMethod.getAnnotation(Raw.class) != null; - } else if (propertyGetter != null) { - storeAsRawType = propertyGetter.getAnnotation(Raw.class) != null; - } else { - storeAsRawType = field.getAnnotation(Raw.class) != null; - } + // At this moment, property getter is the exact getter matching key.localPart (propName). + // Property field may be either exact field matching key.localPart (propName), or more generic one (substitution, any). + //noinspection ConstantConditions + assert propertyGetter != null || propertyField != null; - String fieldName; - if (field != null) { - fieldName = field.getName(); + if (elementFactoryMethod != null) { + storeAsRawType = elementFactoryMethod.getAnnotation(Raw.class) != null; + } else if (propertyGetter != null) { + storeAsRawType = propertyGetter.getAnnotation(Raw.class) != null; } else { - fieldName = propName; + storeAsRawType = propertyField.getAnnotation(Raw.class) != null; } - - Method setter = inspector.findSetter(beanClass, fieldName); - Method getter = null; - boolean wrapInJaxbElement = false; - Class paramType = null; + + if (propertyField != null) { + actualPropertyName = propertyField.getName(); + } else { + actualPropertyName = propName; + } + + return true; + } + + private Method findElementFactoryMethod(String propName) { + Class objectFactoryClass = inspector.getObjectFactoryClass(beanClass.getPackage()); + objectFactory = instantiateObjectFactory(objectFactoryClass); + return inspector.findElementMethodInObjectFactory(objectFactoryClass, propName); + } + + private boolean computeGetterAndSetter(String propName, ParsingContext pc) throws SchemaException { + setter = inspector.findSetter(beanClass, actualPropertyName); + wrapInJaxbElement = false; + paramType = null; if (setter == null) { // No setter. But if the property is multi-value we need to look // for a getter that returns a collection (Collection) - getter = inspector.findPropertyGetter(beanClass, fieldName); + getter = inspector.findPropertyGetter(beanClass, actualPropertyName); if (getter == null) { - String m = "Cannot find setter or getter for field " + fieldName + " in " + beanClass; - if (pc.isCompat()) { - pc.warn(LOGGER, m); - continue; - } else { - throw new SchemaException(m); - } + pc.warnOrThrow(LOGGER, "Cannot find setter or getter for field " + actualPropertyName + " in " + beanClass); + return false; } - Class getterReturnType = getter.getReturnType(); - if (!Collection.class.isAssignableFrom(getterReturnType)) { - throw new SchemaException("Cannot find getter for field "+fieldName+" in "+beanClass+" does not return collection, cannot use it to set value"); + computeParamTypeFromGetter(propName, getter.getReturnType()); + } else { + getter = null; + Class setterType = setter.getParameterTypes()[0]; + computeParamTypeFromSetter(propName, setterType); + } + return true; + } + + private void computeParamTypeFromSetter(String propName, Class setterParamType) { + if (JAXBElement.class.equals(setterParamType)) { + // TODO some handling for the returned generic parameter types + Type[] genericTypes = setter.getGenericParameterTypes(); + if (genericTypes.length != 1) { + throw new IllegalArgumentException("Too lazy to handle this."); } - Type genericReturnType = getter.getGenericReturnType(); - Type typeArgument = getTypeArgument(genericReturnType, "for field "+fieldName+" in "+beanClass+", cannot determine collection type"); - // System.out.println("type argument " + typeArgument); - if (typeArgument instanceof Class) { - paramType = (Class) typeArgument; - } else if (typeArgument instanceof ParameterizedType) { - ParameterizedType paramTypeArgument = (ParameterizedType)typeArgument; - Type rawTypeArgument = paramTypeArgument.getRawType(); - if (rawTypeArgument.equals(JAXBElement.class)) { - // This is the case of Collection> - wrapInJaxbElement = true; - Type innerTypeArgument = getTypeArgument(typeArgument, "for field "+fieldName+" in "+beanClass+", cannot determine collection type (inner type argument)"); - if (innerTypeArgument instanceof Class) { - // This is the case of Collection> - paramType = (Class) innerTypeArgument; - } else if (innerTypeArgument instanceof WildcardType) { - // This is the case of Collection> - // we need to exctract the specific type from the factory method - if (elementMethod == null){ - // TODO: TEMPORARY CODE!!!!!!!!!! fix in 3.1 [med] - Class objectFactoryClass = inspector.getObjectFactoryClass(beanClass.getPackage()); - objectFactory = instantiateObjectFactory(objectFactoryClass); - elementMethod = inspector.findElementMethodInObjectFactory(objectFactoryClass, propName); - if (elementMethod == null) { - throw new IllegalArgumentException("Wildcard type in JAXBElement field specification and no factory method found for field "+fieldName+" in "+beanClass+", cannot determine collection type (inner type argument)"); - } - } - Type factoryMethodGenericReturnType = elementMethod.getGenericReturnType(); - Type factoryMethodTypeArgument = getTypeArgument(factoryMethodGenericReturnType, "in factory method "+elementMethod+" return type for field "+fieldName+" in "+beanClass+", cannot determine collection type"); - if (factoryMethodTypeArgument instanceof Class) { - // This is the case of JAXBElement - paramType = (Class) factoryMethodTypeArgument; - if (Object.class.equals(paramType) && !storeAsRawType) { - throw new IllegalArgumentException("Factory method "+elementMethod+" type argument is Object (and not @Raw) for field "+ - fieldName+" in "+beanClass+", property "+propName); - } - } else { - throw new IllegalArgumentException("Cannot determine factory method return type, got "+factoryMethodTypeArgument+" - for field "+fieldName+" in "+beanClass+", cannot determine collection type (inner type argument)"); - } - } else { - throw new IllegalArgumentException("Ejha! "+innerTypeArgument+" "+innerTypeArgument.getClass()+" from "+getterReturnType+" from "+fieldName+" in "+propName+" "+beanClass); + Type genericType = genericTypes[0]; + if (genericType instanceof ParameterizedType) { + Type actualType = inspector.getTypeArgument(genericType, "add some description"); + if (actualType instanceof WildcardType) { + if (elementFactoryMethod == null) { + elementFactoryMethod = findElementFactoryMethod(propName); } - } else { - // The case of Collection> - if (rawTypeArgument instanceof Class) { - paramType = (Class) rawTypeArgument; + // This is the case of Collection> + // we need to extract the specific type from the factory method + if (elementFactoryMethod == null) { + throw new IllegalArgumentException( + "Wildcard type in JAXBElement field specification and no factory method found for field " + + actualPropertyName + " in " + beanClass + + ", cannot determine collection type (inner type argument)"); + } + Type factoryMethodGenericReturnType = elementFactoryMethod.getGenericReturnType(); + Type factoryMethodTypeArgument = inspector.getTypeArgument(factoryMethodGenericReturnType, + "in factory method " + elementFactoryMethod + " return type for field " + actualPropertyName + + " in " + beanClass + ", cannot determine collection type"); + if (factoryMethodTypeArgument instanceof Class) { + // This is the case of JAXBElement + paramType = (Class) factoryMethodTypeArgument; + if (Object.class.equals(paramType) && !storeAsRawType) { + throw new IllegalArgumentException("Factory method " + elementFactoryMethod + + " type argument is Object (without @Raw) for field " + + actualPropertyName + " in " + beanClass + ", property " + propName); + } } else { - throw new IllegalArgumentException("EH? Eh!? "+typeArgument+" "+typeArgument.getClass()+" from "+getterReturnType+" from "+fieldName+" in "+propName+" "+beanClass); + throw new IllegalArgumentException( + "Cannot determine factory method return type, got " + factoryMethodTypeArgument + + " - for field " + actualPropertyName + " in " + beanClass + + ", cannot determine collection type (inner type argument)"); } } - } else { - throw new IllegalArgumentException("EH? "+typeArgument+" "+typeArgument.getClass()+" from "+getterReturnType+" from "+fieldName+" in "+propName+" "+beanClass); } + // Class enclosing = paramType.getEnclosingClass(); + // Class clazz = paramType.getClass(); + // Class declaring = paramType.getDeclaringClass(); + wrapInJaxbElement = true; } else { - Class setterType = setter.getParameterTypes()[0]; - if (JAXBElement.class.equals(setterType)){ -// TODO some handling for the returned generic parameter types - Type[] genericTypes = setter.getGenericParameterTypes(); - if (genericTypes.length != 1){ - throw new IllegalArgumentException("Too lazy to handle this."); - } - Type genericType = genericTypes[0]; - if (genericType instanceof ParameterizedType){ - Type actualType = getTypeArgument(genericType, "add some description"); - if (actualType instanceof WildcardType) { - if (elementMethod == null) { - Class objectFactoryClass = inspector.getObjectFactoryClass(beanClass.getPackage()); - objectFactory = instantiateObjectFactory(objectFactoryClass); - elementMethod = inspector.findElementMethodInObjectFactory(objectFactoryClass, propName); - } - // This is the case of Collection> - // we need to exctract the specific type from the factory method - if (elementMethod == null) { - throw new IllegalArgumentException("Wildcard type in JAXBElement field specification and no facotry method found for field "+fieldName+" in "+beanClass+", cannot determine collection type (inner type argument)"); - } - Type factoryMethodGenericReturnType = elementMethod.getGenericReturnType(); - Type factoryMethodTypeArgument = getTypeArgument(factoryMethodGenericReturnType, "in factory method "+elementMethod+" return type for field "+fieldName+" in "+beanClass+", cannot determine collection type"); - if (factoryMethodTypeArgument instanceof Class) { - // This is the case of JAXBElement - paramType = (Class) factoryMethodTypeArgument; - if (Object.class.equals(paramType) && !storeAsRawType) { - throw new IllegalArgumentException("Factory method "+elementMethod+" type argument is Object (without @Raw) for field "+ - fieldName+" in "+beanClass+", property "+propName); - } - } else { - throw new IllegalArgumentException("Cannot determine factory method return type, got "+factoryMethodTypeArgument+" - for field "+fieldName+" in "+beanClass+", cannot determine collection type (inner type argument)"); - } - } - } -// Class enclosing = paramType.getEnclosingClass(); -// Class clazz = paramType.getClass(); -// Class declaring = paramType.getDeclaringClass(); - wrapInJaxbElement = true; - } else { - paramType = setterType; - } - } - - if (Element.class.isAssignableFrom(paramType)) { - // DOM! - throw new IllegalArgumentException("DOM not supported in field "+fieldName+" in "+beanClass); - } - - //check for subclasses??? - if (!storeAsRawType && xsubnode != null && xsubnode.getTypeQName() != null) { - Class explicitParamType = getSchemaRegistry().determineCompileTimeClass(xsubnode.getTypeQName()); - if (explicitParamType == null){ - explicitParamType = XsdTypeMapper.toJavaTypeIfKnown(xsubnode.getTypeQName()); - } - - if (explicitParamType != null){ - paramType = explicitParamType; - } + paramType = setterParamType; } + } - - if (!(xsubnode instanceof ListXNode) && Object.class.equals(paramType) && !storeAsRawType) { - throw new IllegalArgumentException("Object property (without @Raw) not supported in field "+fieldName+" in "+beanClass); + private void computeParamTypeFromGetter(String propName, Class getterReturnType) throws SchemaException { + if (!Collection.class.isAssignableFrom(getterReturnType)) { + throw new SchemaException("Cannot find getter for field " + actualPropertyName + " in " + beanClass + + " does not return collection, cannot use it to set value"); } - - String paramNamespace = inspector.determineNamespace(paramType); - - - boolean problem = false; - Object propValue = null; - Collection propValues = null; - if (xsubnode instanceof ListXNode) { - ListXNode xlist = (ListXNode)xsubnode; - if (setter != null) { - try { - propValue = convertSinglePropValue(xsubnode, fieldName, paramType, storeAsRawType, beanClass, paramNamespace, pc); - } catch (SchemaException e) { - problem = processSchemaException(e, xsubnode, pc); - } - } else { - // No setter, we have to use collection getter - propValues = new ArrayList<>(xlist.size()); - for (XNode xsubsubnode: xlist) { - try { - propValues.add(convertSinglePropValue(xsubsubnode, fieldName, paramType, storeAsRawType, beanClass, paramNamespace, pc)); - } catch (SchemaException e) { - problem = processSchemaException(e, xsubsubnode, pc); + // getter.genericReturnType = Collection<...> + Type typeArgument = inspector.getTypeArgument(getter.getGenericReturnType(), + "for field " + actualPropertyName + " in " + beanClass + ", cannot determine collection type"); + if (typeArgument instanceof Class) { + paramType = (Class) typeArgument; // ok, like Collection + } else if (typeArgument instanceof ParameterizedType) { // something more complex + ParameterizedType paramTypeArgument = (ParameterizedType) typeArgument; + Type rawTypeArgument = paramTypeArgument.getRawType(); + if (rawTypeArgument.equals(JAXBElement.class)) { + // This is the case of Collection> + wrapInJaxbElement = true; + Type innerTypeArgument = inspector.getTypeArgument(typeArgument, + "for field " + actualPropertyName + " in " + beanClass + + ", cannot determine collection type (inner type argument)"); + if (innerTypeArgument instanceof Class) { + // This is the case of Collection> (note that wrapInJaxbElement is now true) + paramType = (Class) innerTypeArgument; + } else if (innerTypeArgument instanceof WildcardType) { + // This is the case of Collection> + // we need to extract the specific type from the factory method + if (elementFactoryMethod == null) { + elementFactoryMethod = findElementFactoryMethod(propName); + if (elementFactoryMethod == null) { + throw new IllegalArgumentException( + "Wildcard type in JAXBElement field specification and no factory method found for field " + + actualPropertyName + " in " + beanClass + + ", cannot determine collection type (inner type argument)"); + } + } + // something like JAXBElement + Type factoryMethodGenericReturnType = elementFactoryMethod.getGenericReturnType(); + Type factoryMethodTypeArgument = inspector.getTypeArgument(factoryMethodGenericReturnType, + "in factory method " + elementFactoryMethod + " return type for field " + actualPropertyName + + " in " + beanClass + ", cannot determine collection type"); + if (factoryMethodTypeArgument instanceof Class) { + // This is the case of JAXBElement + paramType = (Class) factoryMethodTypeArgument; + if (Object.class.equals(paramType) && !storeAsRawType) { + throw new IllegalArgumentException("Factory method " + elementFactoryMethod + + " type argument is Object (and not @Raw) for field " + + actualPropertyName + " in " + beanClass + ", property " + propName); + } + } else { + throw new IllegalArgumentException( + "Cannot determine factory method return type, got " + factoryMethodTypeArgument + + " - for field " + actualPropertyName + " in " + beanClass + + ", cannot determine collection type (inner type argument)"); } + } else { + throw new IllegalArgumentException( + "Ejha! " + innerTypeArgument + " " + innerTypeArgument.getClass() + " from " + + getterReturnType + " from " + actualPropertyName + " in " + propName + " " + + beanClass); } - } - } else { - try { - propValue = convertSinglePropValue(xsubnode, fieldName, paramType, storeAsRawType, beanClass, paramNamespace, pc); - } catch (SchemaException e) { - problem = processSchemaException(e, xsubnode, pc); - } - } - - if (setter != null) { - Object value = null; - try { - value = prepareValueToBeStored(propValue, wrapInJaxbElement, objectFactory, elementMethod, propName, beanClass, pc); - setter.invoke(bean, value); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new SystemException("Cannot invoke setter "+setter+" on bean of type "+beanClass+": "+e.getMessage(), e); - } - } else if (getter != null) { - Object getterReturn; - Collection col; - try { - getterReturn = getter.invoke(bean); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new SystemException("Cannot invoke getter "+getter+" on bean of type "+beanClass+": "+e.getMessage(), e); - } - try { - col = (Collection)getterReturn; - } catch (ClassCastException e) { - throw new SystemException("Getter "+getter+" on bean of type "+beanClass+" returned "+getterReturn+" instead of collection"); - } - if (propValue != null) { - col.add(prepareValueToBeStored(propValue, wrapInJaxbElement, objectFactory, elementMethod, propName, beanClass, pc)); - } else if (propValues != null) { - for (Object propVal: propValues) { - col.add(prepareValueToBeStored(propVal, wrapInJaxbElement, objectFactory, elementMethod, propName, beanClass, pc)); + } else { + // The case of Collection> + if (rawTypeArgument instanceof Class) { // ??? rawTypeArgument is the 'Whatever' part + paramType = (Class) rawTypeArgument; + } else { + throw new IllegalArgumentException( + "EH? Eh!? " + typeArgument + " " + typeArgument.getClass() + " from " + getterReturnType + + " from " + actualPropertyName + " in " + propName + " " + beanClass); } - } else if (!problem) { - throw new IllegalStateException("Strange. Multival property "+propName+" in "+beanClass+" produced null values list, parsed from "+xmap); } - checkJaxbElementConsistence(col, pc); } else { - throw new IllegalStateException("Uh? No setter nor getter."); + throw new IllegalArgumentException( + "EH? " + typeArgument + " " + typeArgument.getClass() + " from " + getterReturnType + " from " + + actualPropertyName + " in " + propName + " " + beanClass); } } - - if (prismContext != null && bean instanceof Revivable) { - ((Revivable)bean).revive(prismContext); - } - - return bean; } + private void unmarshalToAnyUsingGetterIfExists(@NotNull T bean, @NotNull QName key, @NotNull XNode node, + @NotNull ParsingContext pc, String propName) throws SchemaException { + Method elementMethod = inspector.findAnyMethod(bean.getClass()); + if (elementMethod != null) { + unmarshallToAnyUsingGetter(bean, elementMethod, key, node, pc); + } else { + pc.warnOrThrow(LOGGER, "No field "+propName+" in class "+bean.getClass()+" (and no element method in object factory too)"); + } + } +// +// if (prismContext != null && bean instanceof Revivable) { +// ((Revivable)bean).revive(prismContext); +// } +// +// return bean; +// } +// // Prepares value to be stored into the bean - e.g. converts PolyString->PolyStringType, wraps a value to JAXB if specified, ... private Object prepareValueToBeStored(Object propVal, boolean wrapInJaxbElement, Object objectFactory, Method factoryMehtod, String propName, Class beanClass, ParsingContext pc) { @@ -493,7 +627,7 @@ private void checkJaxbElementConsistence(Collection collection, ParsingC } } - protected boolean processSchemaException(SchemaException e, XNode xsubnode, ParsingContext pc) throws SchemaException { + private boolean processSchemaException(SchemaException e, XNode xsubnode, ParsingContext pc) throws SchemaException { if (pc.isStrict()) { throw e; } else { @@ -503,9 +637,9 @@ protected boolean processSchemaException(SchemaException e, XNode xsubnode, Pars } } - private void unmarshallToAny(T bean, Method getter, QName elementName, XNode xsubnode, ParsingContext pc) throws SchemaException{ + private void unmarshallToAnyUsingGetter(T bean, Method getter, QName elementName, XNode xsubnode, ParsingContext pc) throws SchemaException{ Class beanClass = (Class) bean.getClass(); - + Class objectFactoryClass = inspector.getObjectFactoryClass(elementName.getNamespaceURI()); Object objectFactory = instantiateObjectFactory(objectFactoryClass); Method elementFactoryMethod = inspector.findElementMethodInObjectFactory(objectFactoryClass, elementName.getLocalPart()); @@ -516,24 +650,23 @@ private void unmarshallToAny(T bean, Method getter, QName elementName, XNo S subBean = unmarshal(xsubSubNode, subBeanClass, pc); unmarshallToAnyValue(bean, beanClass, subBean, objectFactoryClass, objectFactory, elementFactoryMethod, getter, pc); } - } else{ + } else{ S subBean = unmarshal(xsubnode, subBeanClass, pc); unmarshallToAnyValue(bean, beanClass, subBean, objectFactoryClass, objectFactory, elementFactoryMethod, getter, pc); } - } - + private void unmarshallToAnyValue(T bean, Class beanClass, S subBean, Class objectFactoryClass, Object objectFactory, Method elementFactoryMethod, Method getter, ParsingContext pc) { - - + + JAXBElement subBeanElement; try { subBeanElement = (JAXBElement) elementFactoryMethod.invoke(objectFactory, subBean); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { throw new IllegalArgumentException("Cannot invoke factory method "+elementFactoryMethod+" on "+objectFactoryClass+" with "+subBean+": "+e1, e1); } - + Collection col; Object getterReturn; try { @@ -548,12 +681,12 @@ private void unmarshallToAnyValue(T bean, Class beanClass, S subBean, Cla } col.add(subBeanElement != null ? subBeanElement.getValue() : subBeanElement); } - - private void unmarshallToAny(T bean, Field anyField, QName elementName, XNode xsubnode, ParsingContext pc) throws SchemaException{ + + private void unmarshalToAnyUsingField(T bean, Field anyField, QName elementName, XNode xsubnode, ParsingContext pc) throws SchemaException{ Method getter = inspector.findPropertyGetter(bean.getClass(), anyField.getName()); - unmarshallToAny(bean, getter, elementName, xsubnode, pc); + unmarshallToAnyUsingGetter(bean, getter, elementName, xsubnode, pc); } - + private Object instantiateObjectFactory(Class objectFactoryClass) { try { return objectFactoryClass.newInstance(); @@ -562,36 +695,6 @@ private Object instantiateObjectFactory(Class objectFactoryClass) { } } - // parses any subtype of SearchFilterType - private T unmarshalSearchFilterType(MapXNode xmap, Class beanClass, ParsingContext pc) throws SchemaException { - if (xmap == null) { - return null; - } - T filterType; - try { - filterType = beanClass.newInstance(); - } catch (InstantiationException|IllegalAccessException e) { - throw new SystemException("Cannot instantiate " + beanClass + ": " + e.getMessage(), e); - } - filterType.parseFromXNode(xmap, prismContext); - return filterType; - } - - private Type getTypeArgument(Type origType, String desc) { - if (!(origType instanceof ParameterizedType)) { - throw new IllegalArgumentException("No a parametrized type "+desc); - } - ParameterizedType parametrizedType = (ParameterizedType)origType; - Type[] actualTypeArguments = parametrizedType.getActualTypeArguments(); - if (actualTypeArguments == null || actualTypeArguments.length == 0) { - throw new IllegalArgumentException("No type arguments for getter "+desc); - } - if (actualTypeArguments.length > 1) { - throw new IllegalArgumentException("Too many type arguments for getter for "+desc); - } - return actualTypeArguments[0]; - } - private Object convertSinglePropValue(XNode xsubnode, String fieldName, Class paramType, boolean storeAsRawType, Class classType, String schemaNamespace, ParsingContext pc) throws SchemaException { Object propValue; @@ -621,10 +724,8 @@ private Object convertSinglePropValue(XNode xsubnode, String fieldName, Class pa LOGGER.warn("Unknown type name: " + xsubnode.getTypeQName() + ", ignoring it."); } } - if (xsubnode instanceof PrimitiveXNode) { - propValue = unmarshalFromPrimitive(((PrimitiveXNode)xsubnode), paramType, pc); - } else if (xsubnode instanceof MapXNode) { - propValue = unmarshalFromMap((MapXNode)xsubnode, paramType, pc); + if (xsubnode instanceof PrimitiveXNode || xsubnode instanceof MapXNode) { + propValue = unmarshal(xsubnode, paramType, pc); } else if (xsubnode instanceof ListXNode) { ListXNode xlist = (ListXNode)xsubnode; if (xlist.size() > 1) { @@ -643,106 +744,7 @@ private Object convertSinglePropValue(XNode xsubnode, String fieldName, Class pa return propValue; } - public T unmarshalFromPrimitive(PrimitiveXNode xprim, QName typeQName, ParsingContext pc) throws SchemaException { - Class classType = getSchemaRegistry().determineCompileTimeClass(typeQName); - return unmarshalFromPrimitive(xprim, classType, pc); - } - - private T unmarshalFromPrimitive(PrimitiveXNode xprim, Class classType, ParsingContext pc) throws SchemaException { - if (XmlAsStringType.class.equals(classType)) { - return (T) new XmlAsStringType((String) xprim.getParsedValue(DOMUtil.XSD_STRING)); - } - if (XmlTypeConverter.canConvert(classType)) { - // Trivial case, direct conversion - QName xsdType = XsdTypeMapper.toXsdType(classType); - T primValue = postConvertUnmarshall(xprim.getParsedValue(xsdType), pc); - return primValue; - } - - if (RawType.class.isAssignableFrom(classType)) { - RawType rawType = new RawType(xprim, prismContext); - return (T) rawType; - } - - if (PolyStringType.class.isAssignableFrom(classType)) { - // TODO fixme this hack - Object value = xprim.getParsedValue(DOMUtil.XSD_STRING); - PolyString polyString; - if (value instanceof String) { - polyString = new PolyString((String) value); - } else if (value instanceof PolyStringType) { - polyString = ((PolyStringType) value).toPolyString(); - } else if (value instanceof PolyString) { - polyString = (PolyString) value; // TODO clone? - } else if (value == null) { - polyString = null; - } else { - throw new IllegalStateException("Couldn't convert " + value + " to a PolyString; while parsing " + xprim.debugDump()); - } - if (polyString != null) { - // TODO should we always use default normalizer? - polyString.recompute(prismContext.getDefaultPolyStringNormalizer()); - } - return (T) new PolyStringType(polyString); - } - - if (ItemPathType.class.isAssignableFrom(classType)){ - Object parsedValue = xprim.getParsedValue(ItemPathType.COMPLEX_TYPE); - T primValue = postConvertUnmarshall(parsedValue, pc); - return (T) primValue; - } - - if (SearchFilterType.class.isAssignableFrom(classType)){ - throw new SchemaException("Cannot unmarshall search filter from "+xprim); - } - - if (xprim.isEmpty() && !classType.isEnum()) { - // Special case. Just return empty object - try { - return classType.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new SystemException("Cannot instantiate "+classType+": "+e.getMessage(), e); - } - } - - if (!classType.isEnum()) { - throw new SchemaException("Cannot convert primitive value to non-enum bean of type " + classType); - } - // Assume string, maybe TODO extend later - String primValue = (String) xprim.getParsedValue(DOMUtil.XSD_STRING); - if (StringUtils.isBlank(primValue)) { - return null; - } - primValue = StringUtils.trim(primValue); - - String javaEnumString = inspector.findEnumFieldName(classType, primValue); -// for (Field field: classType.getDeclaredFields()) { -// XmlEnumValue xmlEnumValue = field.getAnnotation(XmlEnumValue.class); -// if (xmlEnumValue != null && xmlEnumValue.value() != null && xmlEnumValue.value().equals(primValue)) { -// javaEnumString = field.getName(); -// break; -// } -// } - - if (javaEnumString == null) { - for (Field field: classType.getDeclaredFields()) { - if (field.getName().equals(primValue)) { - javaEnumString = field.getName(); - break; - } - } - } - - if (javaEnumString == null) { - throw new SchemaException("Cannot find enum value for string '"+primValue+"' in "+classType); - } - - T bean = (T) Enum.valueOf((Class)classType, javaEnumString); - - return bean; - } - - private T postConvertUnmarshall(Object parsedPrimValue, ParsingContext pc) { + private T postConvertUnmarshal(Object parsedPrimValue, ParsingContext pc) { if (parsedPrimValue == null) { return null; } @@ -753,80 +755,7 @@ private T postConvertUnmarshall(Object parsedPrimValue, ParsingContext pc) { } } - - public void visit(Object bean, Handler handler) { - if (bean == null) { - return; - } - - Class beanClass = bean.getClass(); - - handler.handle(bean); - - if (beanClass.isEnum() || beanClass.isPrimitive()){ - //nothing more to do - return; - } - - // TODO: implement special handling for RawType, if necessary (it has no XmlType annotation any more) - - XmlType xmlType = beanClass.getAnnotation(XmlType.class); - if (xmlType == null) { - // no @XmlType annotation, we are not interested to go any deeper - return; - } - - List propOrder = inspector.getPropOrder(beanClass); - for (String fieldName: propOrder) { - Method getter = inspector.findPropertyGetter(beanClass, fieldName); - if (getter == null) { - throw new IllegalStateException("No getter for field "+fieldName+" in "+beanClass); - } - Object getterResult; - try { - getterResult = getter.invoke(bean); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new SystemException("Cannot invoke method for field "+fieldName+" in "+beanClass+": "+e.getMessage(), e); - } - - if (getterResult == null) { - continue; - } - - if (getterResult instanceof Collection) { - Collection col = (Collection)getterResult; - if (col.isEmpty()) { - continue; - } - - for (Object element: col) { - visitValue(element, handler); - - } - } else { - visitValue(getterResult, handler); - } - } - } - - private void visitValue(Object element, Handler handler) { - Object elementToMarshall = element; - if (element instanceof JAXBElement){ - elementToMarshall = ((JAXBElement) element).getValue(); - } - visit(elementToMarshall, handler); - } - - private PolyStringType unmarshalPolyStringType(MapXNode xmap) throws SchemaException { - String orig = xmap.getParsedPrimitiveValue(QNameUtil.nullNamespace(PolyString.F_ORIG), DOMUtil.XSD_STRING); - if (orig == null) { - throw new SchemaException("Null polystring orig in "+xmap); - } - String norm = xmap.getParsedPrimitiveValue(QNameUtil.nullNamespace(PolyString.F_NORM), DOMUtil.XSD_STRING); - return new PolyStringType(new PolyString(orig, norm)); - } - - private SchemaDefinitionType unmarshalSchemaDefinitionType(MapXNode xmap) throws SchemaException { + private SchemaDefinitionType unmarshalSchemaDefinitionType(MapXNode xmap, Class beanClass, ParsingContext pc) throws SchemaException { Entry subEntry = xmap.getSingleSubEntry("schema element"); if (subEntry == null) { return null; @@ -838,35 +767,183 @@ private SchemaDefinitionType unmarshalSchemaDefinitionType(MapXNode xmap) throws if (!(xsub instanceof SchemaXNode)) { throw new SchemaException("Cannot parse schema from "+xsub); } -// Element schemaElement = ((SchemaXNode)xsub).getSchemaElement(); -// if (schemaElement == null) { -// throw new SchemaException("Empty schema in "+xsub); -// } - SchemaDefinitionType schemaDefType = unmarshalSchemaDefinitionType((SchemaXNode) xsub); -// new SchemaDefinitionType(); -// schemaDefType.setSchema(schemaElement); - return schemaDefType; + return unmarshalSchemaDefinitionType((SchemaXNode) xsub); } - public SchemaDefinitionType unmarshalSchemaDefinitionType(SchemaXNode xsub) throws SchemaException{ - Element schemaElement = ((SchemaXNode)xsub).getSchemaElement(); + SchemaDefinitionType unmarshalSchemaDefinitionType(SchemaXNode xsub) throws SchemaException{ + Element schemaElement = xsub.getSchemaElement(); if (schemaElement == null) { - throw new SchemaException("Empty schema in "+xsub); + throw new SchemaException("Empty schema in " + xsub); } SchemaDefinitionType schemaDefType = new SchemaDefinitionType(); schemaDefType.setSchema(schemaElement); return schemaDefType; } - public boolean canProcess(QName typeName) { - return ((PrismContextImpl) getPrismContext()).getBeanMarshaller().canProcess(typeName); + @NotNull + public PrismContext getPrismContext() { + return prismContext; } - public boolean canProcess(Class clazz) { - return ((PrismContextImpl) getPrismContext()).getBeanMarshaller().canProcess(clazz); + + @NotNull + private SchemaRegistry getSchemaRegistry() { + return prismContext.getSchemaRegistry(); } - public QName determineTypeForClass(Class clazz) { - return inspector.determineTypeForClass(clazz); + + + //region Specific unmarshallers ========================================================= + + // parses any subtype of SearchFilterType + private T unmarshalSearchFilterType(MapXNode xmap, Class beanClass, ParsingContext pc) throws SchemaException { + if (xmap == null) { + return null; + } + T filterType; + try { + filterType = beanClass.newInstance(); + } catch (InstantiationException|IllegalAccessException e) { + throw new SystemException("Cannot instantiate " + beanClass + ": " + e.getMessage(), e); + } + filterType.parseFromXNode(xmap, prismContext); + return filterType; + } + + private ItemPathType unmarshalItemPath(PrimitiveXNode primitiveXNode, Class beanClass, ParsingContext parsingContext) + throws SchemaException { + Object parsedValue = primitiveXNode.getParsedValue(ItemPathType.COMPLEX_TYPE); + return postConvertUnmarshal(parsedValue, parsingContext); + } + + private Object unmarshalPolyStringFromPrimitive(PrimitiveXNode node, Class beanClass, ParsingContext parsingContext) + throws SchemaException { + Object value = node.getParsedValue(DOMUtil.XSD_STRING); + return toCorrectPolyStringClass(value, beanClass, node); } + private Object unmarshalPolyStringFromMap(MapXNode map, Class beanClass, ParsingContext pc) throws SchemaException { + String orig = map.getParsedPrimitiveValue(QNameUtil.nullNamespace(PolyString.F_ORIG), DOMUtil.XSD_STRING); + if (orig == null) { + throw new SchemaException("Null polystring orig in "+map); + } + String norm = map.getParsedPrimitiveValue(QNameUtil.nullNamespace(PolyString.F_NORM), DOMUtil.XSD_STRING); + Object value = new PolyStringType(new PolyString(orig, norm)); + return toCorrectPolyStringClass(value, beanClass, map); + } + + private Object toCorrectPolyStringClass(Object value, Class beanClass, XNode node) { + PolyString polyString; + if (value instanceof String) { + polyString = new PolyString((String) value); + } else if (value instanceof PolyStringType) { + polyString = ((PolyStringType) value).toPolyString(); + } else if (value instanceof PolyString) { + polyString = (PolyString) value; // TODO clone? + } else if (value == null) { + polyString = null; + } else { + throw new IllegalStateException("Couldn't convert " + value + " to a PolyString; while parsing " + node.debugDump()); + } + if (polyString != null && polyString.getNorm() == null) { + // TODO should we always use default normalizer? + polyString.recompute(prismContext.getDefaultPolyStringNormalizer()); + } + if (PolyString.class.equals(beanClass)) { + return polyString; + } else if (PolyStringType.class.equals(beanClass)) { + return new PolyStringType(polyString); + } else { + throw new IllegalArgumentException("Wrong class for PolyString value: " + beanClass); + } + } + + private Object notSupported(XNode node, Class beanClass, ParsingContext parsingContext) { + // TODO what if compat mode? + throw new IllegalArgumentException("The following couldn't be parsed as " + beanClass + ": " + node.debugDump()); + } + + private XmlAsStringType unmarshalXmlAsStringFromPrimitive(PrimitiveXNode node, Class beanClass, ParsingContext parsingContext) throws SchemaException { + return new XmlAsStringType(((PrimitiveXNode) node).getParsedValue(DOMUtil.XSD_STRING)); + } + + private XmlAsStringType unmarshalXmlAsStringFromMap(MapXNode map, Class beanClass, ParsingContext parsingContext) throws SchemaException { + // reading a string represented a XML-style content + // used e.g. when reading report templates (embedded XML) + // A necessary condition: there may be only one map entry. + if (map.size() > 1) { + throw new SchemaException("Map with more than one item cannot be parsed as a string: " + map); + } else if (map.isEmpty()) { + return new XmlAsStringType(); + } else { + Entry entry = map.entrySet().iterator().next(); + DomLexicalProcessor domParser = ((PrismContextImpl) prismContext).getParserDom(); + String value = domParser.write(entry.getValue(), entry.getKey(), null); + return new XmlAsStringType(value); + } + } + + private RawType unmarshalRawType(XNode node, Class beanClass, ParsingContext parsingContext) { + // TODO We could probably try to parse the raw node content using information from explicit node type. + return new RawType(node, prismContext); + } + + private T unmarshalEnumFromPrimitive(PrimitiveXNode prim, Class beanClass, ParsingContext pc) + throws SchemaException { + + String primValue = (String) prim.getParsedValue(DOMUtil.XSD_STRING); + primValue = StringUtils.trim(primValue); + if (StringUtils.isEmpty(primValue)) { + return null; + } + + String javaEnumString = inspector.findEnumFieldName(beanClass, primValue); + if (javaEnumString == null) { + for (Field field: beanClass.getDeclaredFields()) { + if (field.getName().equals(primValue)) { + javaEnumString = field.getName(); + break; + } + } + } + if (javaEnumString == null) { + throw new SchemaException("Cannot find enum value for string '"+primValue+"' in "+beanClass); + } + + @SuppressWarnings("unchecked") + T bean = (T) Enum.valueOf((Class)beanClass, javaEnumString); + return bean; + } + + private ProtectedStringType unmarshalProtectedString(MapXNode map, Class beanClass, ParsingContext pc) throws SchemaException { + ProtectedStringType protectedType = new ProtectedStringType(); + XNodeProcessorUtil.parseProtectedType(protectedType, map, prismContext, pc); + return protectedType; + } + + private ProtectedStringType unmarshalProtectedString(PrimitiveXNode prim, Class beanClass, ParsingContext pc) throws SchemaException { + ProtectedStringType protectedType = new ProtectedStringType(); + protectedType.setClearValue(prim.getParsedValue(DOMUtil.XSD_STRING)); + return protectedType; + } + + private ProtectedByteArrayType unmarshalProtectedByteArray(MapXNode map, Class beanClass, ParsingContext pc) throws SchemaException { + ProtectedByteArrayType protectedType = new ProtectedByteArrayType(); + XNodeProcessorUtil.parseProtectedType(protectedType, map, prismContext, pc); + return protectedType; + } + + private ProtectedByteArrayType unmarshalProtectedByteArray(PrimitiveXNode prim, Class beanClass, ParsingContext pc) throws SchemaException { + ProtectedByteArrayType protectedType = new ProtectedByteArrayType(); + String stringValue = prim.getParsedValue(DOMUtil.XSD_STRING); + if (stringValue == null) { + return null; + } + try { + protectedType.setClearValue(ArrayUtils.toObject(stringValue.getBytes("UTF-8"))); + } catch (UnsupportedEncodingException e) { + throw new SystemException("UTF-8 encoding is not supported", e); + } + return protectedType; + } + //endregion } \ No newline at end of file diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismBeanInspector.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismBeanInspector.java index a3a086b173b..6e66b9afedd 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismBeanInspector.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismBeanInspector.java @@ -40,6 +40,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -186,23 +188,14 @@ public List get(Class c) { private Map> _findElementMethodInObjectFactory = Collections.synchronizedMap(new HashMap()); Method findElementMethodInObjectFactory(Class objectFactoryClass, String propName) { - return find2(_findElementMethodInObjectFactory, objectFactoryClass, propName, new Getter2() { - @Override - public Method get(Class c, String p) { - return findElementMethodInObjectFactoryUncached(c, p); - } - }); + return find2(_findElementMethodInObjectFactory, objectFactoryClass, propName, + (c, p) -> findElementMethodInObjectFactoryUncached(c, p)); } private Map> _lookupSubstitution = Collections.synchronizedMap(new HashMap()); Field lookupSubstitution(Class beanClass, Method elementMethod) { - return find2(_lookupSubstitution, beanClass, elementMethod, new Getter2() { - @Override - public Field get(Class c, Method m) { - return lookupSubstitutionUncached(c, m); - } - }); + return find2(_lookupSubstitution, beanClass, elementMethod, (c, m) -> lookupSubstitutionUncached(c, m)); } private Map> _findEnumFieldName = Collections.synchronizedMap(new HashMap()); @@ -247,23 +240,13 @@ public QName get(String fieldName, Class beanClass, String def private Map> _findPropertyGetter = Collections.synchronizedMap(new HashMap()); public Method findPropertyGetter(Class beanClass, String propName) { - return find2(_findPropertyGetter, beanClass, propName, new Getter2() { - @Override - public Method get(Class param1, String param2) { - return findPropertyGetterUncached(param1, param2); - } - }); + return find2(_findPropertyGetter, beanClass, propName, (param1, param2) -> findPropertyGetterUncached(param1, param2)); } private Map> _findPropertyField = Collections.synchronizedMap(new HashMap()); public Field findPropertyField(Class beanClass, String propName) { - return find2(_findPropertyField, beanClass, propName, new Getter2() { - @Override - public Field get(Class param1, String param2) { - return findPropertyFieldUncached(param1, param2); - } - }); + return find2(_findPropertyField, beanClass, propName, (param1, param2) -> findPropertyFieldUncached(param1, param2)); } //endregion @@ -307,11 +290,11 @@ private Method findPropertyGetterUncached(Class classType, String propNam } for (Method method: classType.getDeclaredMethods()) { XmlElement xmlElement = method.getAnnotation(XmlElement.class); - if (xmlElement != null && xmlElement.name() != null && xmlElement.name().equals(propName)) { + if (xmlElement != null && xmlElement.name().equals(propName)) { return method; } XmlAttribute xmlAttribute = method.getAnnotation(XmlAttribute.class); - if (xmlAttribute != null && xmlAttribute.name() != null && xmlAttribute.name().equals(propName)) { + if (xmlAttribute != null && xmlAttribute.name().equals(propName)) { return method; } } @@ -457,28 +440,15 @@ private Method findElementMethodInObjectFactoryUncached(Class objectFactoryClass return null; } - private Field lookupSubstitutionUncached(Class beanClass, Method elementMethod) { - XmlElementDecl xmlElementDecl = elementMethod.getAnnotation(XmlElementDecl.class); + private Field lookupSubstitutionUncached(Class beanClass, Method elementMethodInObjectFactory) { + XmlElementDecl xmlElementDecl = elementMethodInObjectFactory.getAnnotation(XmlElementDecl.class); if (xmlElementDecl == null) { return null; } final String substitutionHeadName = xmlElementDecl.substitutionHeadName(); - if (substitutionHeadName == null) { - return null; - } - return findField(beanClass,new Handler() { - @Override - public boolean handle(Field field) { - XmlElementRef xmlElementRef = field.getAnnotation(XmlElementRef.class); - if (xmlElementRef == null) { - return false; - } - String name = xmlElementRef.name(); - if (name == null) { - return false; - } - return name.equals(substitutionHeadName); - } + return findField(beanClass, field -> { + XmlElementRef xmlElementRef = field.getAnnotation(XmlElementRef.class); + return xmlElementRef != null && xmlElementRef.name().equals(substitutionHeadName); }); } @@ -669,11 +639,22 @@ public boolean handle(Field field) { } public Method findAnyMethod(Class beanClass) { - return findMethod(beanClass, new Handler() { - @Override - public boolean handle(Method method) { - return (method.getAnnotation(XmlAnyElement.class) != null); - } - }); + return findMethod(beanClass, method -> (method.getAnnotation(XmlAnyElement.class) != null)); + } + + // e.g. Collection -> UserType + Type getTypeArgument(Type origType, String desc) { + if (!(origType instanceof ParameterizedType)) { + throw new IllegalArgumentException("Not a parametrized type "+desc); + } + ParameterizedType parametrizedType = (ParameterizedType)origType; + Type[] actualTypeArguments = parametrizedType.getActualTypeArguments(); + if (actualTypeArguments == null || actualTypeArguments.length == 0) { + throw new IllegalArgumentException("No type arguments for getter "+desc); + } + if (actualTypeArguments.length > 1) { + throw new IllegalArgumentException("Too many type arguments for getter for "+desc); + } + return actualTypeArguments[0]; } } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismMarshaller.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismMarshaller.java index 8424e500a6c..81b9bfab93b 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismMarshaller.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismMarshaller.java @@ -47,10 +47,10 @@ */ public class PrismMarshaller { - @NotNull private final BeanMarshaller beanConverter; + @NotNull private final BeanMarshaller beanMarshaller; - public PrismMarshaller(@NotNull BeanMarshaller beanConverter) { - this.beanConverter = beanConverter; + public PrismMarshaller(@NotNull BeanMarshaller beanMarshaller) { + this.beanMarshaller = beanMarshaller; } //region Public interface ====================================================================================== @@ -122,15 +122,24 @@ RootXNode marshalPrismValueAsRoot(@NotNull PrismValue value, QName itemName, Ite RootXNode marshalAnyData(@NotNull Object object, QName itemName, ItemDefinition itemDefinition, SerializationContext context) throws SchemaException { if (object instanceof Item) { return marshalItemAsRoot((Item) object, itemName, itemDefinition, context); - } else { - Validate.notNull(itemName, "itemName must be specified for non-Item objects"); - XNode valueNode = beanConverter.marshall(object, context); // TODO item definition! + } + Validate.notNull(itemName, "itemName must be specified for non-Item objects"); + if (object instanceof Objectable) { + return marshalItemAsRoot(((Objectable) object).asPrismObject(), itemName, null, context); + } else if (object instanceof Containerable) { + return marshalPrismValueAsRoot(((Containerable) object).asPrismContainerValue(), itemName, null, context); + } else if (beanMarshaller.canProcess(object.getClass())) { + XNode valueNode = beanMarshaller.marshall(object, context); // TODO item definition! QName typeName = JAXBUtil.getTypeQName(object.getClass()); - addTypeDefinitionIfNeeded(itemName, typeName, valueNode); - if (valueNode.getTypeQName() == null && typeName == null) { - throw new SchemaException("No type QName for class " + object.getClass()); - } + if (valueNode != null) { + addTypeDefinitionIfNeeded(itemName, typeName, valueNode); + if (valueNode.getTypeQName() == null && typeName == null) { + throw new SchemaException("No type QName for class " + object.getClass()); + } + } // TODO or else put type name at least to root? (but, can valueNode be null if object is not null?) return new RootXNode(itemName, valueNode); + } else { + throw new IllegalArgumentException("Couldn't serialize " + object); } } @@ -138,7 +147,7 @@ public boolean canSerialize(Object object) { if (object instanceof Item) { return true; } else { - return beanConverter.canProcess(object.getClass()); + return beanMarshaller.canProcess(object.getClass()); } } @@ -382,8 +391,8 @@ private XNode serializePropertyValue(@NotNull PrismPropertyValue value, P T realValue = value.getValue(); if (realValue instanceof PolyString) { return serializePolyString((PolyString) realValue); - } else if (beanConverter.canProcess(typeName)) { - XNode xnode = beanConverter.marshall(realValue); + } else if (beanMarshaller.canProcess(typeName)) { + XNode xnode = beanMarshaller.marshall(realValue); // // why is this? // if (realValue instanceof ProtectedDataType && (definition == null || definition.isDynamic())) { // xnode.setExplicitTypeDeclaration(true); @@ -410,7 +419,7 @@ private XNode serializePropertyRawValue(PrismPropertyValue value) throws } T realValue = value.getValue(); if (realValue != null) { - return createPrimitiveXNode(realValue, DOMUtil.XSD_STRING); + return createPrimitiveXNode(realValue, null); } else { throw new IllegalStateException("Neither real nor raw value present in " + value); } @@ -435,10 +444,10 @@ private PrimitiveXNode createPrimitiveXNode(T val, QName type) { @NotNull private SchemaRegistry getSchemaRegistry() { - return beanConverter.getPrismContext().getSchemaRegistry(); + return beanMarshaller.getPrismContext().getSchemaRegistry(); } - private void addTypeDefinitionIfNeeded(@NotNull QName itemName, QName typeName, XNode valueNode) { + private void addTypeDefinitionIfNeeded(@NotNull QName itemName, QName typeName, @NotNull XNode valueNode) { if (valueNode.getTypeQName() != null && valueNode.isExplicitTypeDeclaration()) { return; // already set } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismUnmarshaller.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismUnmarshaller.java index 6f9a06caad2..77f0117893d 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismUnmarshaller.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/PrismUnmarshaller.java @@ -15,47 +15,34 @@ */ package com.evolveum.midpoint.prism.marshaller; -import java.util.Collection; -import java.util.Map.Entry; - -import javax.xml.XMLConstants; -import javax.xml.namespace.QName; - import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.schema.PrismSchema; import com.evolveum.midpoint.prism.schema.SchemaRegistry; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; - -import com.evolveum.prism.xml.ns._public.types_3.RawType; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang.Validate; - -import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.util.PrismUtil; -import com.evolveum.midpoint.prism.xnode.ListXNode; -import com.evolveum.midpoint.prism.xnode.MapXNode; -import com.evolveum.midpoint.prism.xnode.PrimitiveXNode; -import com.evolveum.midpoint.prism.xnode.RootXNode; -import com.evolveum.midpoint.prism.xnode.SchemaXNode; -import com.evolveum.midpoint.prism.xnode.XNode; +import com.evolveum.midpoint.prism.xnode.*; import com.evolveum.midpoint.util.DOMUtil; -import com.evolveum.midpoint.util.DisplayableValue; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; import com.evolveum.prism.xml.ns._public.types_3.EvaluationTimeType; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.SchemaDefinitionType; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang.Validate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import java.util.Map.Entry; + public class PrismUnmarshaller { private static final Trace LOGGER = TraceManager.getTrace(PrismUnmarshaller.class); - public static final QName ARTIFICIAL_OBJECT_NAME = new QName(XMLConstants.NULL_NS_URI, "anObject"); + private static final QName ARTIFICIAL_OBJECT_NAME = new QName(XMLConstants.NULL_NS_URI, "anObject"); @NotNull private PrismContext prismContext; @@ -293,7 +280,7 @@ private PrismProperty parseProperty(@NotNull XNode node, @NotNull QName i PrismProperty property = itemDefinition != null ? itemDefinition.instantiate() : - new PrismProperty(itemName, prismContext); + new PrismProperty<>(itemName, prismContext); if (node instanceof ListXNode) { ListXNode listNode = (ListXNode) node; @@ -325,114 +312,39 @@ private PrismProperty parseProperty(@NotNull XNode node, @NotNull QName i // if definition == null or any AND node has type defined, this type must be non-containerable (fit into PPV) private PrismPropertyValue parsePropertyValue(@NotNull XNode node, @Nullable PrismPropertyDefinition definition, @NotNull ParsingContext pc) throws SchemaException { - - if (definition == null || definition.isAnyType()) { - if (node.getTypeQName() == null) { - return PrismPropertyValue.createRaw(node); - } - // TODO FIX/TEST THIS UGLY HACK - if (node instanceof PrimitiveXNode) { - PrimitiveXNode prim = (PrimitiveXNode) node; - prim.parseValue(node.getTypeQName(), pc.getEvaluationMode()); - if (prim.getValue() != null) { - return new PrismPropertyValue<>((T) prim.getValue()); - } else { - return null; - } - } else if (node instanceof MapXNode) { - if (getBeanUnmarshaller().canProcess(node.getTypeQName())) { - T value = getBeanUnmarshaller().unmarshal((MapXNode) node, node.getTypeQName(), pc); - if (value instanceof Containerable) { - throw new IllegalStateException("Cannot store containerable into prism property: " + node.debugDump()); - } else { - return new PrismPropertyValue<>(value); - } - } else { - // TODO or should treat this elsewhere? - throw new IllegalStateException("Cannot parse as " + node.getTypeQName() + ": " + node.debugDump()); - } - } else { - throw new IllegalArgumentException("Unexpected node: " + node.debugDump()); + QName typeName = + getSchemaRegistry().selectMoreSpecific( + definition != null && !definition.isAnyType() ? definition.getTypeName() : null, + node.getTypeQName() + ); + if (typeName == null) { + return PrismPropertyValue.createRaw(node); + } else if (getBeanUnmarshaller().canProcess(typeName)) { + T realValue = getBeanUnmarshaller().unmarshal(node, typeName, pc); + // Postprocessing after returning from unmarshaller. It speaks bean language (e.g. PolyStringType, not PolyString). + // It also doesn't know about prism-specific things like allowed values, etc. + if (realValue instanceof PolyStringType) { + @SuppressWarnings("unchecked") + T valueT = (T) ((PolyStringType) realValue).toPolyString(); + realValue = valueT; } - } - - T realValue; - if (node instanceof PrimitiveXNode) { - @SuppressWarnings("unchecked") - PrimitiveXNode primitiveNode = (PrimitiveXNode) node; - realValue = parsePropertyRealValueFromPrimitive(primitiveNode, definition, pc); - } else if (node instanceof MapXNode) { - realValue = parsePropertyRealValueFromMap((MapXNode) node, definition, pc); - } else { - throw new IllegalArgumentException("Cannot parse property value from " + node.debugDump()); - } - return realValue != null ? new PrismPropertyValue(realValue) : null; - } - - private T parsePropertyRealValueFromPrimitive(@NotNull PrimitiveXNode primitiveNode, - @NotNull PrismPropertyDefinition definition, @NotNull ParsingContext pc) throws SchemaException { - - QName typeName = definition.getTypeName(); - T realValue; - if (getBeanUnmarshaller().canProcess(typeName)) { - // Primitive elements may also have complex Java representations (e.g. enums) - realValue = getBeanUnmarshaller().unmarshalFromPrimitive(primitiveNode, typeName, pc); - } else if (!DOMUtil.XSD_ANYTYPE.equals(typeName)) { - try { - realValue = primitiveNode.getParsedValue(typeName, pc.getEvaluationMode()); - } catch (SchemaException e) { - pc.warnOrThrow(LOGGER, "Couldn't parse primitive value of type " + typeName + ". Value: " + primitiveNode.getStringValue() - + ".\nDefinition: " + definition.debugDump(), e); + PrismUtil.recomputeRealValue(realValue, prismContext); + if (!isValueAllowed(realValue, definition)) { + pc.warnOrThrow(LOGGER, "Skipping unknown value of type " + typeName + ". Value: " + realValue); return null; } + return realValue != null ? new PrismPropertyValue<>(realValue) : null; } else { - realValue = (T) RawType.create(primitiveNode, prismContext); + throw new IllegalStateException("Cannot parse as " + typeName + ": " + node.debugDump()); } - - if (!(realValue instanceof RawType) && !isValueAllowed(realValue, definition.getAllowedValues())) { - pc.warnOrThrow(LOGGER, "Skipping unknown value of type " + typeName + ". Value: " + primitiveNode.getStringValue()); - return null; - } - - if (realValue == null) { - return null; - } else if (realValue instanceof PolyStringType) { - PolyStringType polyStringType = (PolyStringType) realValue; - realValue = (T) new PolyString(polyStringType.getOrig(), polyStringType.getNorm()); - } else if (realValue instanceof String && typeName.equals(PolyStringType.COMPLEX_TYPE)) { - String val = (String) realValue; - realValue = (T) new PolyString(val); - } - - PrismUtil.recomputeRealValue(realValue, prismContext); - return realValue; } - private T parsePropertyRealValueFromMap(@NotNull MapXNode xmap, @NotNull PrismPropertyDefinition propertyDefinition, - @NotNull ParsingContext pc) - throws SchemaException { - QName typeName = propertyDefinition.getTypeName(); - if (getBeanUnmarshaller().canProcess(typeName)) { - return getBeanUnmarshaller().unmarshal(xmap, typeName, pc); - } else { - if (propertyDefinition.isRuntimeSchema()) { - throw new SchemaException("Complex run-time properties are not supported: type " + typeName + " from " + xmap); - } else { - throw new SystemException("Cannot parse compile-time property " + propertyDefinition.getName() + " type " + typeName + " from " + xmap); - } - } - } - - private boolean isValueAllowed(T realValue, Collection> collection) { - if (CollectionUtils.isEmpty(collection)) { + private boolean isValueAllowed(T realValue, PrismPropertyDefinition definition) { + if (definition == null || CollectionUtils.isEmpty(definition.getAllowedValues())) { return true; } - for (DisplayableValue o : collection) { - if (realValue.equals(o.getValue())) { - return true; - } - } - return false; + return definition.getAllowedValues().stream() + .anyMatch(displayableValue -> realValue.equals(displayableValue.getValue())); } @NotNull @@ -525,7 +437,7 @@ private PrismReferenceValue parseReferenceValueAsReference(@NotNull XNode xnode, refVal.setDescription(map.getParsedPrimitiveValue(XNode.KEY_REFERENCE_DESCRIPTION, DOMUtil.XSD_STRING)); - refVal.setFilter(parseFilter(map.get(XNode.KEY_REFERENCE_FILTER), pc)); + refVal.setFilter(parseFilter(map.get(XNode.KEY_REFERENCE_FILTER))); String resolutionTimeString = map.getParsedPrimitiveValue(XNode.KEY_REFERENCE_RESOLUTION_TIME, DOMUtil.XSD_STRING); if (resolutionTimeString != null) { @@ -608,7 +520,7 @@ private PrismReferenceValue parseReferenceValueAsCompositeObject(XNode node, return refVal; } - private SearchFilterType parseFilter(XNode xnode, ParsingContext pc) throws SchemaException { + private SearchFilterType parseFilter(XNode xnode) throws SchemaException { if (xnode == null) { return null; } @@ -618,7 +530,7 @@ private SearchFilterType parseFilter(XNode xnode, ParsingContext pc) throws Sche return SearchFilterType.createFromXNode(xnode, prismContext); } - private ItemDefinition locateItemDefinition(@NotNull QName itemName, + private ItemDefinition locateItemDefinition(@NotNull QName itemName, @Nullable ComplexTypeDefinition complexTypeDefinition, XNode xnode) throws SchemaException { return getSchemaRegistry() diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/QueryConvertor.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/QueryConvertor.java index e7769dfa9ba..ac9ca4afb68 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/QueryConvertor.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/QueryConvertor.java @@ -28,6 +28,7 @@ import com.evolveum.midpoint.prism.xnode.*; import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import com.evolveum.prism.xml.ns._public.types_3.ObjectReferenceType; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; @@ -591,7 +592,8 @@ private static ItemPath getPath(MapXNode clauseXMap, QName key) throws SchemaExc if (!(xnode instanceof PrimitiveXNode)) { throw new SchemaException("Expected that field "+key+" will be primitive, but it is "+xnode.getDesc()); } - return clauseXMap.getParsedPrimitiveValue(key, ItemPath.XSD_TYPE); + ItemPathType itemPathType = clauseXMap.getParsedPrimitiveValue(key, ItemPathType.COMPLEX_TYPE); + return itemPathType != null ? itemPathType.getItemPath() : null; } private static QName getMatchingRule(MapXNode xmap) throws SchemaException{ @@ -788,7 +790,7 @@ private static MapXNode seriali map.put(ELEMENT_VALUE, valuesNode); } if (filter.getRightHandSidePath() != null) { - map.put(ELEMENT_RIGHT_HAND_SIDE_PATH, createPrimitiveXNode(filter.getRightHandSidePath(), ItemPath.XSD_TYPE)); + map.put(ELEMENT_RIGHT_HAND_SIDE_PATH, createPrimitiveXNode(filter.getRightHandSidePath().asItemPathType(), ItemPathType.COMPLEX_TYPE)); } ExpressionWrapper xexpression = filter.getExpression(); @@ -877,7 +879,7 @@ private static void serializePath(MapXNode map, ItemPath path, ObjectFilter filt if (path == null) { throw new IllegalStateException("Cannot serialize filter " + filter + " because it does not contain path"); } - map.put(ELEMENT_PATH, createPrimitiveXNode(path, ItemPath.XSD_TYPE)); + map.put(ELEMENT_PATH, createPrimitiveXNode(path.asItemPathType(), ItemPathType.COMPLEX_TYPE)); } private static XNode serializePropertyValue(PrismPropertyValue value, PrismPropertyDefinition definition, BeanMarshaller beanConverter) throws SchemaException { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/XPathHolder.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/XPathHolder.java index 87c7fcd6074..6a5da74591d 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/XPathHolder.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/marshaller/XPathHolder.java @@ -34,6 +34,7 @@ import com.evolveum.midpoint.util.QNameUtil; import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -447,6 +448,7 @@ public List toSegments() { return Collections.unmodifiableList(segments); } + @NotNull public ItemPath toItemPath() { List xsegments = toSegments(); List segments = new ArrayList(xsegments.size()); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java index b2eae6022d2..9d9988335d1 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java @@ -37,8 +37,10 @@ * */ public class ItemPath implements Serializable, Cloneable { - + + @Deprecated // use ItemPathType.COMPLEX_TYPE public static final QName XSD_TYPE = ItemPathType.COMPLEX_TYPE; + public static final ItemPath EMPTY_PATH = new ItemPath(); private List segments; @@ -680,4 +682,9 @@ public static void checkNoReferences(ItemPath path) { } } + public ItemPathType asItemPathType() { + return new ItemPathType(this); + } + + } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistry.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistry.java index 6a2e150549c..98c2a24c831 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistry.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistry.java @@ -80,7 +80,7 @@ ItemDefinition locateItemDefinition(@NotNull QName ite Class getCompileTimeClass(QName xsdType); - PrismSchema findSchemaByCompileTimeClass(Class compileTimeClass); + PrismSchema findSchemaByCompileTimeClass(@NotNull Class compileTimeClass); /** * Tries to determine type name for any class (primitive, complex one). @@ -136,7 +136,7 @@ T findItemDefinitionByFullPath(Class PrismObject instantiate(Class compileTimeClass) throws SchemaException; // Takes XSD types into account as well - Class determineClassForType(QName type); + Class determineClassForType(QName type); // Takes XSD types into account as well Class determineClassForItemDefinition(ItemDefinition itemDefinition); @@ -144,6 +144,9 @@ T findItemDefinitionByFullPath(Class ID selectMoreSpecific(ID def1, ID def2) throws SchemaException; + QName selectMoreSpecific(QName type1, QName type2) + throws SchemaException; + enum ComparisonResult { EQUAL, // types are equal NO_STATIC_CLASS, // static class cannot be determined diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistryImpl.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistryImpl.java index cdbf99bc672..acafedb223f 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistryImpl.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/schema/SchemaRegistryImpl.java @@ -43,6 +43,7 @@ import com.evolveum.midpoint.prism.xml.XsdTypeMapper; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.prism.xml.ns._public.types_3.ObjectType; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import org.apache.commons.lang.StringUtils; import org.apache.xml.resolver.Catalog; import org.apache.xml.resolver.CatalogManager; @@ -1085,8 +1086,11 @@ public Collection getSchemaDescriptions() { @Override - public PrismSchema findSchemaByCompileTimeClass(Class compileTimeClass) { + public PrismSchema findSchemaByCompileTimeClass(@NotNull Class compileTimeClass) { Package compileTimePackage = compileTimeClass.getPackage(); + if (compileTimePackage == null) { + System.out.println("Hi"); + } for (SchemaDescription desc: schemaDescriptions) { if (compileTimePackage.equals(desc.getCompileTimeClassesPackage())) { PrismSchema schema = desc.getSchema(); @@ -1207,7 +1211,7 @@ public QName determineTypeForClass(Class clazz) { } @Override - public Class determineClassForType(QName type) { + public Class determineClassForType(QName type) { if (XmlTypeConverter.canConvert(type)) { return XsdTypeMapper.toJavaType(type); } else { @@ -1254,6 +1258,41 @@ public ID selectMoreSpecific(ID def1, ID def2) + " (" + cls1 + ") and " + def2.getTypeName() + " (" + cls2 + ")"); } + @Override + public QName selectMoreSpecific(QName type1, QName type2) + throws SchemaException { + if (type1 == null || QNameUtil.match(type1, DOMUtil.XSD_ANYTYPE)) { + return type2; + } + if (type2 == null || QNameUtil.match(type2, DOMUtil.XSD_ANYTYPE)) { + return type1; + } + if (QNameUtil.match(type1, type2)) { + return type1; + } + Class cls1 = determineClassForType(type1); + Class cls2 = determineClassForType(type2); + if (cls1 == null || cls2 == null) { + throw new SchemaException("Couldn't find more specific type from " + type1 + + " (" + cls1 + ") and " + type2 + " (" + cls2 + ")"); + } + if (cls1.isAssignableFrom(cls2)) { + return type2; + } + if (cls2.isAssignableFrom(cls1)) { + return type1; + } + // poly string vs string + if (PolyStringType.class.equals(cls1) || String.class.equals(cls2)) { + return type1; + } + if (PolyStringType.class.equals(cls2) || String.class.equals(cls1)) { + return type2; + } + throw new SchemaException("Couldn't find more specific type from " + type1 + + " (" + cls1 + ") and " + type2 + " (" + cls2 + ")"); + } + @Override public ComparisonResult compareDefinitions(@NotNull ID def1, @NotNull ID def2) throws SchemaException { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XsdTypeMapper.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XsdTypeMapper.java index 126e23c25c0..c7a1a604756 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XsdTypeMapper.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XsdTypeMapper.java @@ -88,11 +88,12 @@ private static void initTypeMap() throws IOException, ClassNotFoundException { addMapping(XMLGregorianCalendar.class, DOMUtil.XSD_DATETIME, true); addMapping(Duration.class, DOMUtil.XSD_DURATION, true); - addMapping(ItemPath.class, ItemPath.XSD_TYPE, true); + addMapping(ItemPathType.class, ItemPathType.COMPLEX_TYPE, true); + addMapping(ItemPath.class, ItemPathType.COMPLEX_TYPE, false); addMapping(QName.class, DOMUtil.XSD_QNAME, true); addMapping(PolyString.class, PrismConstants.POLYSTRING_TYPE_QNAME, true); - addMappingExt(ItemPathType.class, ItemPathType.COMPLEX_TYPE, true); + addMappingExt(ItemPathType.class, ItemPathType.COMPLEX_TYPE, true); // TODO remove xsdToJavaTypeMap.put(DOMUtil.XSD_ANYURI, String.class); } diff --git a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ItemPathType.java b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ItemPathType.java index 1226329f090..543f727f65d 100644 --- a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ItemPathType.java +++ b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ItemPathType.java @@ -157,4 +157,15 @@ public int hashCode() { public String toString() { return getItemPath().toString(); } + + // temporary implementation until things settle down + public static ItemPathType asItemPathType(Object value) { + if (value instanceof ItemPathType) { + return (ItemPathType) value; + } else if (value instanceof ItemPath) { + return ((ItemPath) value).asItemPathType(); + } else { + throw new IllegalArgumentException("Value " + value + " is neither ItemPath nor ItemPathType."); + } + } } diff --git a/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestPrismParsing.java b/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestPrismParsing.java index 4d25c49b2fa..55596a04ab6 100644 --- a/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestPrismParsing.java +++ b/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestPrismParsing.java @@ -352,7 +352,7 @@ public void test410UserWillRoundTrip() throws Exception { assertUserWill(user); // WHEN - String serialized = prismContext.serializeObjectToString(user, getOutputFormat()); + String serialized = prismContext.serializerFor(getOutputFormat()).serialize(user); // THEN assertNotNull(serialized); diff --git a/infra/prism/src/test/java/com/evolveum/midpoint/prism/lex/TestProtectedString.java b/infra/prism/src/test/java/com/evolveum/midpoint/prism/lex/TestProtectedString.java index d2e0cca94f3..02338435e9d 100644 --- a/infra/prism/src/test/java/com/evolveum/midpoint/prism/lex/TestProtectedString.java +++ b/infra/prism/src/test/java/com/evolveum/midpoint/prism/lex/TestProtectedString.java @@ -64,7 +64,7 @@ public void testParseProtectedString() throws Exception { // WHEN - MapXNode protectedStringTypeXNode = ((PrismContextImpl) prismContext).getBeanMarshaller().marshalProtectedDataType(protectedStringType); + MapXNode protectedStringTypeXNode = ((PrismContextImpl) prismContext).getBeanMarshaller().marshalProtectedDataType(protectedStringType, null); System.out.println("Protected string type XNode: " + protectedStringTypeXNode.debugDump()); // THEN diff --git a/infra/prism/src/test/resources/common/yaml/user-will.yaml b/infra/prism/src/test/resources/common/yaml/user-will.yaml index ab07236e9a1..49f3da4c5d7 100644 --- a/infra/prism/src/test/resources/common/yaml/user-will.yaml +++ b/infra/prism/src/test/resources/common/yaml/user-will.yaml @@ -21,7 +21,7 @@ user: dateType: - 170721000000 durationType: - - ! "P17Y3M2D" + - "P17Y3M2D" locations: - location: - key: "sk" diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/MiscSchemaUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/MiscSchemaUtil.java index 2821fe59478..a6496118f17 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/MiscSchemaUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/MiscSchemaUtil.java @@ -391,7 +391,7 @@ public static void serializeFaultMessage(Detail detail, FaultMessage faultMessag XNode faultMessageXnode = marshaller.marshall(faultMessage.getFaultInfo()); // TODO RootXNode xroot = new RootXNode(SchemaConstants.FAULT_MESSAGE_ELEMENT_NAME, faultMessageXnode); xroot.setExplicitTypeDeclaration(true); - QName faultType = marshaller.determineTypeForClass(faultMessage.getFaultInfo().getClass()); + QName faultType = prismContext.getSchemaRegistry().determineTypeForClass(faultMessage.getFaultInfo().getClass()); xroot.setTypeQName(faultType); ((PrismContextImpl) prismContext).getParserDom().serializeUnderElement(xroot, SchemaConstants.FAULT_MESSAGE_ELEMENT_NAME, detail); } catch (SchemaException e) { diff --git a/repo/repo-sql-impl-test/src/test/resources/basic/user-big.xml b/repo/repo-sql-impl-test/src/test/resources/basic/user-big.xml index d6301372c07..da0c0a3549d 100644 --- a/repo/repo-sql-impl-test/src/test/resources/basic/user-big.xml +++ b/repo/repo-sql-impl-test/src/test/resources/basic/user-big.xml @@ -19,8 +19,9 @@ xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3" xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:xsd="http://www.w3.org/2001/XMLSchema"> - + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3"> + testuserX123 testuserx123 @@ -139,7 +140,7 @@ xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2001/04/xmlenc#" - xsi:type="c:ProtectedStringType"> + xsi:type="t:ProtectedStringType">