You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by pa...@apache.org on 2017/04/03 14:04:18 UTC

[1/2] polygene-java git commit: Introduce @ConvertedBy(ConverterType.class) annotation

Repository: polygene-java
Updated Branches:
  refs/heads/develop ef01c64ea -> 52ece384c


Introduce @ConvertedBy(ConverterType.class) annotation

Converters must be assembled as objects.
@ConvertedBy can be put on plain types or on Property state methods.
See AbstractConvertersSerializationTest for sample usage.
Supported by javax.json, javax.xml and MessagePack extensions.


Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/c6b4ac3d
Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/c6b4ac3d
Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/c6b4ac3d

Branch: refs/heads/develop
Commit: c6b4ac3da15dd1c3b20df4c3fbed3c06c01d5bce
Parents: ef01c64
Author: Paul Merlin <pa...@apache.org>
Authored: Mon Apr 3 15:20:52 2017 +0200
Committer: Paul Merlin <pa...@apache.org>
Committed: Mon Apr 3 15:20:52 2017 +0200

----------------------------------------------------------------------
 .../polygene/api/serialization/ConvertedBy.java |  37 +++++
 .../javaxjson/JavaxJsonDeserializer.java        |  20 ++-
 .../javaxjson/JavaxJsonSerializer.java          |  25 ++-
 .../AbstractConvertersSerializationTest.java    | 159 +++++++++++++++++++
 .../JavaxJsonConvertersSerializationTest.java   |  45 ++++++
 .../javaxxml/JavaxXmlDeserializer.java          |  20 ++-
 .../javaxxml/JavaxXmlSerializer.java            |  17 ++
 ...avaxXmlConfigurationDeserializationTest.java |  24 ++-
 .../JavaxXmlConvertersSerializationTest.java    |  67 ++++++++
 .../JavaxXmlPlainValueSerializationTest.java    |   7 +-
 .../messagepack/MessagePackDeserializer.java    |  38 +++--
 .../messagepack/MessagePackSerializer.java      |  27 +++-
 .../MessagePackConvertersSerializationTest.java |  44 +++++
 13 files changed, 503 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/core/api/src/main/java/org/apache/polygene/api/serialization/ConvertedBy.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/serialization/ConvertedBy.java b/core/api/src/main/java/org/apache/polygene/api/serialization/ConvertedBy.java
new file mode 100644
index 0000000..3559314
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/serialization/ConvertedBy.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.polygene.api.serialization;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Convert this type or Property with the given {@link Converter}.
+ *
+ * The {@link Converter} must be assembled as an object and will automatically be instantiated by the Polygene runtime.
+ */
+@Retention( RetentionPolicy.RUNTIME )
+@Target( { ElementType.TYPE, ElementType.METHOD } )
+@Documented
+public @interface ConvertedBy
+{
+    Class<? extends Converter> value();
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java
index 06bb8c8..be3699e 100644
--- a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java
+++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java
@@ -47,6 +47,7 @@ import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.injection.scope.Uses;
 import org.apache.polygene.api.mixin.Initializable;
 import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.serialization.ConvertedBy;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
 import org.apache.polygene.api.serialization.SerializationException;
@@ -57,6 +58,7 @@ import org.apache.polygene.api.type.CollectionType;
 import org.apache.polygene.api.type.MapType;
 import org.apache.polygene.api.type.ValueCompositeType;
 import org.apache.polygene.api.type.ValueType;
+import org.apache.polygene.api.util.Annotations;
 import org.apache.polygene.api.value.ValueBuilder;
 import org.apache.polygene.api.value.ValueDescriptor;
 import org.apache.polygene.spi.serialization.AbstractTextDeserializer;
@@ -184,6 +186,12 @@ public class JavaxJsonDeserializer extends AbstractTextDeserializer
         {
             return null;
         }
+        ConvertedBy convertedBy = Annotations.annotationOn( valueType.primaryType(), ConvertedBy.class );
+        if( convertedBy != null )
+        {
+            return (T) module.instance().newObject( convertedBy.value() )
+                             .fromString( doDeserialize( module, ValueType.STRING, json ).toString() );
+        }
         Converter<Object> converter = converters.converterFor( valueType );
         if( converter != null )
         {
@@ -339,7 +347,17 @@ public class JavaxJsonDeserializer extends AbstractTextDeserializer
             JsonValue jsonValue = object.get( property.qualifiedName().name() );
             if( jsonValue != null )
             {
-                Object value = doDeserialize( module, property.valueType(), jsonValue );
+                Object value;
+                ConvertedBy convertedBy = property.metaInfo( ConvertedBy.class );
+                if( convertedBy != null )
+                {
+                    value = module.instance().newObject( convertedBy.value() )
+                                  .fromString( doDeserialize( module, ValueType.STRING, jsonValue ) );
+                }
+                else
+                {
+                    value = doDeserialize( module, property.valueType(), jsonValue );
+                }
                 if( property.isImmutable() )
                 {
                     if( value instanceof Set )

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java
index dcc2db8..8e34d0d 100644
--- a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java
+++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java
@@ -36,16 +36,20 @@ import org.apache.polygene.api.PolygeneAPI;
 import org.apache.polygene.api.association.AssociationStateHolder;
 import org.apache.polygene.api.common.Optional;
 import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.injection.scope.Structure;
 import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.injection.scope.Uses;
 import org.apache.polygene.api.mixin.Initializable;
+import org.apache.polygene.api.serialization.ConvertedBy;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
 import org.apache.polygene.api.service.ServiceDescriptor;
+import org.apache.polygene.api.structure.Module;
 import org.apache.polygene.api.type.ArrayType;
 import org.apache.polygene.api.type.MapType;
 import org.apache.polygene.api.type.ValueCompositeType;
 import org.apache.polygene.api.type.ValueType;
+import org.apache.polygene.api.util.Annotations;
 import org.apache.polygene.api.util.ArrayIterable;
 import org.apache.polygene.api.value.ValueComposite;
 import org.apache.polygene.api.value.ValueDescriptor;
@@ -71,6 +75,9 @@ public class JavaxJsonSerializer extends AbstractTextSerializer
     @Uses
     private ServiceDescriptor descriptor;
 
+    @Structure
+    private Module module;
+
     private JavaxJsonSettings settings;
 
     @Override
@@ -119,6 +126,11 @@ public class JavaxJsonSerializer extends AbstractTextSerializer
             return JsonValue.NULL;
         }
         Class<?> objectClass = object.getClass();
+        ConvertedBy convertedBy = Annotations.annotationOn( objectClass, ConvertedBy.class );
+        if( convertedBy != null )
+        {
+            return doSerialize( options, module.newObject( convertedBy.value() ).toString( object ), false );
+        }
         Converter<Object> converter = converters.converterFor( objectClass );
         if( converter != null )
         {
@@ -164,9 +176,16 @@ public class JavaxJsonSerializer extends AbstractTextSerializer
 
         JsonObjectBuilder builder = jsonFactories.builderFactory().createObjectBuilder();
         valueType.properties().forEach(
-            property -> builder.add(
-                property.qualifiedName().name(),
-                doSerialize( options, state.propertyFor( property.accessor() ).get(), false ) ) );
+            property ->
+            {
+                Object value = state.propertyFor( property.accessor() ).get();
+                ConvertedBy convertedBy = property.metaInfo( ConvertedBy.class );
+                if( convertedBy != null )
+                {
+                    value = module.newObject( convertedBy.value() ).toString( value );
+                }
+                builder.add( property.qualifiedName().name(), doSerialize( options, value, false ) );
+            } );
         valueType.associations().forEach(
             association -> builder.add(
                 association.qualifiedName().name(),

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/core/testsupport/src/main/java/org/apache/polygene/test/serialization/AbstractConvertersSerializationTest.java
----------------------------------------------------------------------
diff --git a/core/testsupport/src/main/java/org/apache/polygene/test/serialization/AbstractConvertersSerializationTest.java b/core/testsupport/src/main/java/org/apache/polygene/test/serialization/AbstractConvertersSerializationTest.java
new file mode 100644
index 0000000..f8b6834
--- /dev/null
+++ b/core/testsupport/src/main/java/org/apache/polygene/test/serialization/AbstractConvertersSerializationTest.java
@@ -0,0 +1,159 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.polygene.test.serialization;
+
+import java.util.Objects;
+import org.apache.polygene.api.injection.scope.Service;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.serialization.ConvertedBy;
+import org.apache.polygene.api.serialization.Converter;
+import org.apache.polygene.api.serialization.Serialization;
+import org.apache.polygene.api.value.ValueBuilder;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.test.AbstractPolygeneTest;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+public abstract class AbstractConvertersSerializationTest extends AbstractPolygeneTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+    {
+        module.values( SomeValue.class );
+        module.objects( CustomPlainValueConverter.class, CustomPropertyConverter.class );
+    }
+
+    protected abstract String getStringFromValueState( String state, String key ) throws Exception;
+
+    public interface SomeValue
+    {
+        Property<CustomPlainValue> customPlainValue();
+
+        @ConvertedBy( CustomPropertyConverter.class )
+        Property<String> customConvertedProperty();
+    }
+
+    @ConvertedBy( CustomPlainValueConverter.class )
+    public static class CustomPlainValue
+    {
+        private final String state;
+
+        CustomPlainValue( String state )
+        {
+            this.state = state;
+        }
+
+        public String getState()
+        {
+            return state;
+        }
+
+        @Override
+        public boolean equals( final Object o )
+        {
+            if( this == o ) { return true; }
+            if( o == null || getClass() != o.getClass() ) { return false; }
+            CustomPlainValue that = (CustomPlainValue) o;
+            return Objects.equals( state, that.state );
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return Objects.hash( state );
+        }
+    }
+
+    public static class CustomPlainValueConverter implements Converter<CustomPlainValue>
+    {
+        @Override
+        public Class<CustomPlainValue> type()
+        {
+            return CustomPlainValue.class;
+        }
+
+        @Override
+        public String toString( CustomPlainValue object )
+        {
+            return rot13( object.getState() );
+        }
+
+        @Override
+        public CustomPlainValue fromString( String string )
+        {
+            return new CustomPlainValue( rot13( string ) );
+        }
+    }
+
+    public static class CustomPropertyConverter implements Converter<String>
+    {
+        @Override
+        public Class<String> type()
+        {
+            return String.class;
+        }
+
+        @Override
+        public String toString( String object )
+        {
+            return rot13( object );
+        }
+
+        @Override
+        public String fromString( String string )
+        {
+            return rot13( string );
+        }
+    }
+
+    @Service
+    private Serialization serialization;
+
+    @Test
+    public void testConvertedByAnnotation() throws Exception
+    {
+        ValueBuilder<SomeValue> builder = valueBuilderFactory.newValueBuilder( SomeValue.class );
+        builder.prototype().customPlainValue().set( new CustomPlainValue( "foo" ) );
+        builder.prototype().customConvertedProperty().set( "bar" );
+        SomeValue value = builder.newInstance();
+
+        String serialized = serialization.serialize( value );
+        assertThat( getStringFromValueState( serialized, "customPlainValue" ), equalTo( rot13( "foo" ) ) );
+        assertThat( getStringFromValueState( serialized, "customConvertedProperty" ), equalTo( rot13( "bar" ) ) );
+
+        SomeValue deserialized = serialization.deserialize( module, SomeValue.class, serialized );
+        assertThat( deserialized, equalTo( value ) );
+    }
+
+    private static String rot13( String string )
+    {
+        StringBuilder builder = new StringBuilder();
+        for( int i = 0; i < string.length(); i++ )
+        {
+            char c = string.charAt( i );
+            if( c >= 'a' && c <= 'm' ) { c += 13; }
+            else if( c >= 'A' && c <= 'M' ) { c += 13; }
+            else if( c >= 'n' && c <= 'z' ) { c -= 13; }
+            else if( c >= 'N' && c <= 'Z' ) { c -= 13; }
+            builder.append( c );
+        }
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/JavaxJsonConvertersSerializationTest.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/JavaxJsonConvertersSerializationTest.java b/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/JavaxJsonConvertersSerializationTest.java
new file mode 100644
index 0000000..6076faf
--- /dev/null
+++ b/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/JavaxJsonConvertersSerializationTest.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.polygene.serialization.javaxjson;
+
+import java.io.StringReader;
+import javax.json.JsonObject;
+import org.apache.polygene.api.injection.scope.Service;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.serialization.javaxjson.assembly.JavaxJsonSerializationAssembler;
+import org.apache.polygene.test.serialization.AbstractConvertersSerializationTest;
+
+public class JavaxJsonConvertersSerializationTest extends AbstractConvertersSerializationTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+    {
+        new JavaxJsonSerializationAssembler().assemble( module );
+        super.assemble( module );
+    }
+
+    @Service
+    private JavaxJsonFactories jsonFactories;
+
+    @Override
+    protected String getStringFromValueState( String state, String key ) throws Exception
+    {
+        JsonObject jsonObject = jsonFactories.readerFactory().createReader( new StringReader( state ) ).readObject();
+        return jsonObject.getString( key );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
index 9acdfe0..3561d1e 100644
--- a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
+++ b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
@@ -43,6 +43,7 @@ import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.injection.scope.Uses;
 import org.apache.polygene.api.mixin.Initializable;
 import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.serialization.ConvertedBy;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
 import org.apache.polygene.api.serialization.SerializationException;
@@ -54,6 +55,7 @@ import org.apache.polygene.api.type.EnumType;
 import org.apache.polygene.api.type.MapType;
 import org.apache.polygene.api.type.ValueCompositeType;
 import org.apache.polygene.api.type.ValueType;
+import org.apache.polygene.api.util.Annotations;
 import org.apache.polygene.api.value.ValueBuilder;
 import org.apache.polygene.api.value.ValueDescriptor;
 import org.apache.polygene.spi.serialization.AbstractTextDeserializer;
@@ -131,6 +133,12 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer
         {
             return null;
         }
+        ConvertedBy convertedBy = Annotations.annotationOn( valueType.primaryType(), ConvertedBy.class );
+        if( convertedBy != null )
+        {
+            return (T) module.instance().newObject( convertedBy.value() )
+                             .fromString( doDeserialize( module, ValueType.STRING, xml ).toString() );
+        }
         Converter<Object> converter = converters.converterFor( valueType );
         if( converter != null )
         {
@@ -195,7 +203,17 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer
             if( element.isPresent() )
             {
                 Node valueNode = JavaxXml.firstStateChildNode( element.get() ).orElse( null );
-                Object value = doDeserialize( module, property.valueType(), valueNode );
+                Object value;
+                ConvertedBy convertedBy = property.metaInfo( ConvertedBy.class );
+                if( convertedBy != null )
+                {
+                    value = module.instance().newObject( convertedBy.value() )
+                                  .fromString( doDeserialize( module, ValueType.STRING, valueNode ) );
+                }
+                else
+                {
+                    value = doDeserialize( module, property.valueType(), valueNode );
+                }
                 if( property.isImmutable() )
                 {
                     if( value instanceof Set )

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
index 5331f0f..fa3895d 100644
--- a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
+++ b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
@@ -33,17 +33,21 @@ import org.apache.polygene.api.association.AssociationStateHolder;
 import org.apache.polygene.api.common.Optional;
 import org.apache.polygene.api.composite.CompositeInstance;
 import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.injection.scope.Structure;
 import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.injection.scope.Uses;
 import org.apache.polygene.api.mixin.Initializable;
+import org.apache.polygene.api.serialization.ConvertedBy;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
 import org.apache.polygene.api.serialization.SerializationException;
 import org.apache.polygene.api.service.ServiceDescriptor;
+import org.apache.polygene.api.structure.Module;
 import org.apache.polygene.api.type.ArrayType;
 import org.apache.polygene.api.type.EnumType;
 import org.apache.polygene.api.type.MapType;
 import org.apache.polygene.api.type.ValueCompositeType;
+import org.apache.polygene.api.util.Annotations;
 import org.apache.polygene.api.util.ArrayIterable;
 import org.apache.polygene.api.value.ValueComposite;
 import org.apache.polygene.api.value.ValueDescriptor;
@@ -77,6 +81,9 @@ public class JavaxXmlSerializer extends AbstractTextSerializer
     @Uses
     private ServiceDescriptor descriptor;
 
+    @Structure
+    private Module module;
+
     private JavaxXmlSettings settings;
 
     @Override
@@ -139,6 +146,11 @@ public class JavaxXmlSerializer extends AbstractTextSerializer
             return document.createElement( NULL_ELEMENT_NAME );
         }
         Class<?> objectClass = object.getClass();
+        ConvertedBy convertedBy = Annotations.annotationOn( objectClass, ConvertedBy.class );
+        if( convertedBy != null )
+        {
+            return doSerialize( document, options, module.newObject( convertedBy.value() ).toString( object ), false );
+        }
         Converter<Object> converter = converters.converterFor( objectClass );
         if( converter != null )
         {
@@ -190,6 +202,11 @@ public class JavaxXmlSerializer extends AbstractTextSerializer
             property ->
             {
                 Object value = state.propertyFor( property.accessor() ).get();
+                ConvertedBy convertedBy = property.metaInfo( ConvertedBy.class );
+                if( convertedBy != null )
+                {
+                    value = module.newObject( convertedBy.value() ).toString( value );
+                }
                 Element element = document.createElement( property.qualifiedName().name() );
                 element.appendChild( doSerialize( document, options, value, false ) );
                 valueElement.appendChild( element );

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConfigurationDeserializationTest.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConfigurationDeserializationTest.java b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConfigurationDeserializationTest.java
index 2a1fbfb..6e1a236 100644
--- a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConfigurationDeserializationTest.java
+++ b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConfigurationDeserializationTest.java
@@ -1,9 +1,25 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 package org.apache.polygene.serialization.javaxxml;
 
 import org.apache.polygene.bootstrap.ModuleAssembly;
 import org.apache.polygene.serialization.javaxxml.assembly.JavaxXmlSerializationAssembler;
 import org.apache.polygene.test.entity.AbstractConfigurationDeserializationTest;
-import org.junit.Test;
 
 public class JavaxXmlConfigurationDeserializationTest extends AbstractConfigurationDeserializationTest
 {
@@ -13,10 +29,4 @@ public class JavaxXmlConfigurationDeserializationTest extends AbstractConfigurat
         new JavaxXmlSerializationAssembler().assemble( module );
         super.assemble( module );
     }
-
-    @Test
-    public void givenServiceWhenInitializingExpectCorrectDeserialization()
-    {
-        super.givenServiceWhenInitializingExpectCorrectDeserialization();
-    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConvertersSerializationTest.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConvertersSerializationTest.java b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConvertersSerializationTest.java
new file mode 100644
index 0000000..1562665
--- /dev/null
+++ b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlConvertersSerializationTest.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.polygene.serialization.javaxxml;
+
+import java.io.StringReader;
+import java.util.Optional;
+import javax.xml.parsers.DocumentBuilder;
+import org.apache.polygene.api.injection.scope.Service;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.serialization.javaxxml.assembly.JavaxXmlSerializationAssembler;
+import org.apache.polygene.test.serialization.AbstractConvertersSerializationTest;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+
+public class JavaxXmlConvertersSerializationTest extends AbstractConvertersSerializationTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+    {
+        new JavaxXmlSerializationAssembler().assemble( module );
+        super.assemble( module );
+    }
+
+    @Service
+    private JavaxXmlFactories xmlFactories;
+
+    @Override
+    protected String getStringFromValueState( String state, String key ) throws Exception
+    {
+        JavaxXmlSettings settings = serviceFinder.findService( JavaxXmlSerialization.class )
+                                                 .metaInfo( JavaxXmlSettings.class );
+        settings = JavaxXmlSettings.orDefault( settings );
+        DocumentBuilder docBuilder = xmlFactories.documentBuilderFactory().newDocumentBuilder();
+        Document doc = docBuilder.parse( new InputSource( new StringReader( state ) ) );
+        Optional<Element> stateElement = JavaxXml.firstChildElementNamed( doc, settings.getRootTagName() );
+        if( stateElement.isPresent() )
+        {
+            Optional<Element> valueNode = JavaxXml.firstChildElementNamed( stateElement.get(),
+                                                                           settings.getValueTagName() );
+            if( valueNode.isPresent() )
+            {
+                Optional<Element> element = JavaxXml.firstChildElementNamed( valueNode.get(), key );
+                if( element.isPresent() )
+                {
+                    return element.get().getFirstChild().getNodeValue();
+                }
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlPlainValueSerializationTest.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlPlainValueSerializationTest.java b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlPlainValueSerializationTest.java
index 8de45f5..dd55670 100644
--- a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlPlainValueSerializationTest.java
+++ b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlPlainValueSerializationTest.java
@@ -22,7 +22,7 @@ package org.apache.polygene.serialization.javaxxml;
 import java.io.StringReader;
 import java.util.Optional;
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.polygene.api.injection.scope.Service;
 import org.apache.polygene.bootstrap.ModuleAssembly;
 import org.apache.polygene.serialization.javaxxml.assembly.JavaxXmlSerializationAssembler;
 import org.apache.polygene.test.serialization.AbstractPlainValueSerializationTest;
@@ -40,13 +40,16 @@ public class JavaxXmlPlainValueSerializationTest extends AbstractPlainValueSeria
                                             .assemble( module );
     }
 
+    @Service
+    private JavaxXmlFactories xmlFactories;
+
     @Override
     protected String getSingleStringRawState( String state ) throws Exception
     {
         JavaxXmlSettings settings = serviceFinder.findService( JavaxXmlSerialization.class )
                                                  .metaInfo( JavaxXmlSettings.class );
         settings = JavaxXmlSettings.orDefault( settings );
-        DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        DocumentBuilder docBuilder = xmlFactories.documentBuilderFactory().newDocumentBuilder();
         Document doc = docBuilder.parse( new InputSource( new StringReader( state ) ) );
         Optional<Element> stateElement = JavaxXml.firstChildElementNamed( doc, settings.getRootTagName() );
         if( stateElement.isPresent() )

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackDeserializer.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackDeserializer.java b/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackDeserializer.java
index d74b0a4..507eb6a 100644
--- a/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackDeserializer.java
+++ b/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackDeserializer.java
@@ -37,6 +37,7 @@ import org.apache.polygene.api.entity.EntityReference;
 import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.mixin.Mixins;
 import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.serialization.ConvertedBy;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
 import org.apache.polygene.api.serialization.Deserializer;
@@ -48,6 +49,7 @@ import org.apache.polygene.api.type.EnumType;
 import org.apache.polygene.api.type.MapType;
 import org.apache.polygene.api.type.ValueCompositeType;
 import org.apache.polygene.api.type.ValueType;
+import org.apache.polygene.api.util.Annotations;
 import org.apache.polygene.api.value.ValueBuilder;
 import org.apache.polygene.api.value.ValueDescriptor;
 import org.apache.polygene.spi.serialization.AbstractBinaryDeserializer;
@@ -102,6 +104,12 @@ public interface MessagePackDeserializer extends Deserializer
                 {
                     return null;
                 }
+                ConvertedBy convertedBy = Annotations.annotationOn( valueType.primaryType(), ConvertedBy.class );
+                if( convertedBy != null )
+                {
+                    return (T) module.instance().newObject( convertedBy.value() )
+                                     .fromString( doDeserialize( module, ValueType.STRING, value ).toString() );
+                }
                 Converter<Object> converter = converters.converterFor( valueType );
                 if( converter != null )
                 {
@@ -222,26 +230,36 @@ public interface MessagePackDeserializer extends Deserializer
         {
             return property ->
             {
-                Value value = namedValues.get( property.qualifiedName().name() );
-                if( value != null )
+                Value messagePackValue = namedValues.get( property.qualifiedName().name() );
+                if( messagePackValue != null )
                 {
-                    Object propertyValue = doDeserialize( module, property.valueType(), value );
+                    Object value;
+                    ConvertedBy convertedBy = property.metaInfo( ConvertedBy.class );
+                    if( convertedBy != null )
+                    {
+                        value = module.instance().newObject( convertedBy.value() )
+                                      .fromString( doDeserialize( module, ValueType.STRING, messagePackValue ) );
+                    }
+                    else
+                    {
+                        value = doDeserialize( module, property.valueType(), messagePackValue );
+                    }
                     if( property.isImmutable() )
                     {
-                        if( propertyValue instanceof Set )
+                        if( value instanceof Set )
                         {
-                            return unmodifiableSet( (Set<?>) propertyValue );
+                            return unmodifiableSet( (Set<?>) value );
                         }
-                        else if( propertyValue instanceof List )
+                        else if( value instanceof List )
                         {
-                            return unmodifiableList( (List<?>) propertyValue );
+                            return unmodifiableList( (List<?>) value );
                         }
-                        else if( propertyValue instanceof Map )
+                        else if( value instanceof Map )
                         {
-                            return unmodifiableMap( (Map<?, ?>) propertyValue );
+                            return unmodifiableMap( (Map<?, ?>) value );
                         }
                     }
-                    return propertyValue;
+                    return value;
                 }
                 return property.resolveInitialValue( module );
             };

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackSerializer.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackSerializer.java b/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackSerializer.java
index 40b924b..c48b7f7 100644
--- a/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackSerializer.java
+++ b/extensions/serialization-messagepack/src/main/java/org/apache/polygene/serialization/messagepack/MessagePackSerializer.java
@@ -26,16 +26,20 @@ import org.apache.polygene.api.PolygeneAPI;
 import org.apache.polygene.api.association.AssociationStateHolder;
 import org.apache.polygene.api.common.Optional;
 import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.injection.scope.Structure;
 import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.api.serialization.ConvertedBy;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
 import org.apache.polygene.api.serialization.SerializationException;
 import org.apache.polygene.api.serialization.Serializer;
+import org.apache.polygene.api.structure.Module;
 import org.apache.polygene.api.type.ArrayType;
 import org.apache.polygene.api.type.EnumType;
 import org.apache.polygene.api.type.MapType;
 import org.apache.polygene.api.type.ValueCompositeType;
+import org.apache.polygene.api.util.Annotations;
 import org.apache.polygene.api.util.ArrayIterable;
 import org.apache.polygene.api.value.ValueComposite;
 import org.apache.polygene.api.value.ValueDescriptor;
@@ -61,6 +65,9 @@ public interface MessagePackSerializer extends Serializer
         @This
         private MessagePackAdapters adapters;
 
+        @Structure
+        private Module module;
+
         @Override
         public void serialize( Options options, OutputStream output, @Optional Object object )
         {
@@ -86,6 +93,11 @@ public interface MessagePackSerializer extends Serializer
                     return ValueFactory.newNil();
                 }
                 Class<?> objectClass = object.getClass();
+                ConvertedBy convertedBy = Annotations.annotationOn( objectClass, ConvertedBy.class );
+                if( convertedBy != null )
+                {
+                    return doSerialize( options, module.newObject( convertedBy.value() ).toString( object ), false );
+                }
                 Converter<Object> converter = converters.converterFor( objectClass );
                 if( converter != null )
                 {
@@ -138,9 +150,18 @@ public interface MessagePackSerializer extends Serializer
 
             ValueFactory.MapBuilder builder = ValueFactory.newMapBuilder();
             valueType.properties().forEach(
-                property -> builder.put(
-                    ValueFactory.newString( property.qualifiedName().name() ),
-                    doSerialize( options, state.propertyFor( property.accessor() ).get(), false ) ) );
+                property ->
+                {
+                    Object value = state.propertyFor( property.accessor() ).get();
+                    ConvertedBy convertedBy = property.metaInfo( ConvertedBy.class );
+                    if( convertedBy != null )
+                    {
+                        value = module.newObject( convertedBy.value() ).toString( value );
+                    }
+                    builder.put(
+                        ValueFactory.newString( property.qualifiedName().name() ),
+                        doSerialize( options, value, false ) );
+                } );
             valueType.associations().forEach(
                 association -> builder.put(
                     ValueFactory.newString( association.qualifiedName().name() ),

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c6b4ac3d/extensions/serialization-messagepack/src/test/java/org/apache/polygene/serialization/messagepack/MessagePackConvertersSerializationTest.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-messagepack/src/test/java/org/apache/polygene/serialization/messagepack/MessagePackConvertersSerializationTest.java b/extensions/serialization-messagepack/src/test/java/org/apache/polygene/serialization/messagepack/MessagePackConvertersSerializationTest.java
new file mode 100644
index 0000000..305d958
--- /dev/null
+++ b/extensions/serialization-messagepack/src/test/java/org/apache/polygene/serialization/messagepack/MessagePackConvertersSerializationTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.polygene.serialization.messagepack;
+
+import java.util.Base64;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.serialization.messagepack.assembly.MessagePackSerializationAssembler;
+import org.apache.polygene.test.serialization.AbstractConvertersSerializationTest;
+import org.msgpack.core.MessagePack;
+import org.msgpack.value.ValueFactory;
+
+public class MessagePackConvertersSerializationTest extends AbstractConvertersSerializationTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+    {
+        new MessagePackSerializationAssembler().assemble( module );
+        super.assemble( module );
+    }
+
+    @Override
+    protected String getStringFromValueState( String state, String key ) throws Exception
+    {
+        return MessagePack.newDefaultUnpacker( Base64.getDecoder().decode( state ) )
+                          .unpackValue().asMapValue()
+                          .map().get( ValueFactory.newString( key ) )
+                          .asStringValue().asString();
+    }
+}


[2/2] polygene-java git commit: build: fix signing ignore conditions to make CI checkDist job happy

Posted by pa...@apache.org.
build: fix signing ignore conditions to make CI checkDist job happy


Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/52ece384
Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/52ece384
Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/52ece384

Branch: refs/heads/develop
Commit: 52ece384c84460300bafdee662b3f56324202840
Parents: c6b4ac3
Author: Paul Merlin <pa...@apache.org>
Authored: Mon Apr 3 15:30:30 2017 +0200
Committer: Paul Merlin <pa...@apache.org>
Committed: Mon Apr 3 15:30:30 2017 +0200

----------------------------------------------------------------------
 .../apache/polygene/gradle/code/PublishingPlugin.groovy   |  4 ++--
 .../structure/distributions/DistributionsPlugin.groovy    | 10 +++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/52ece384/buildSrc/src/main/groovy/org/apache/polygene/gradle/code/PublishingPlugin.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/apache/polygene/gradle/code/PublishingPlugin.groovy b/buildSrc/src/main/groovy/org/apache/polygene/gradle/code/PublishingPlugin.groovy
index 8f48922..be239b8 100644
--- a/buildSrc/src/main/groovy/org/apache/polygene/gradle/code/PublishingPlugin.groovy
+++ b/buildSrc/src/main/groovy/org/apache/polygene/gradle/code/PublishingPlugin.groovy
@@ -117,10 +117,10 @@ class PublishingPlugin implements Plugin<Project>
   {
     project.plugins.apply 'signing'
     def signing = project.extensions.getByType SigningExtension
-    signing.required = config.signed
+    signing.required = config.signed && !project.findProperty( 'skipSigning' )
     signing.sign project.configurations.getByName( 'archives' )
     def signArchives = project.tasks.getByName( 'signArchives' ) as Sign
-    signArchives.enabled = config.signed
+    signArchives.enabled = config.signed && !project.findProperty( 'skipSigning' )
     signArchives.onlyIf { !project.findProperty( 'skipSigning' ) }
   }
 

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/52ece384/buildSrc/src/main/groovy/org/apache/polygene/gradle/structure/distributions/DistributionsPlugin.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/apache/polygene/gradle/structure/distributions/DistributionsPlugin.groovy b/buildSrc/src/main/groovy/org/apache/polygene/gradle/structure/distributions/DistributionsPlugin.groovy
index ab62df6..23a3fb6 100644
--- a/buildSrc/src/main/groovy/org/apache/polygene/gradle/structure/distributions/DistributionsPlugin.groovy
+++ b/buildSrc/src/main/groovy/org/apache/polygene/gradle/structure/distributions/DistributionsPlugin.groovy
@@ -436,15 +436,15 @@ class DistributionsPlugin implements Plugin<Project>
     def releaseSpec = project.extensions.getByType( ReleaseSpecExtension )
     project.plugins.apply 'signing'
     def signing = project.extensions.getByType SigningExtension
-    signing.required = !releaseSpec.developmentVersion
-    def distTasks = [TaskNames.ZIP_SOURCE_DIST, TaskNames.TAR_SOURCE_DIST,
-                     TaskNames.ZIP_BINARY_DIST, TaskNames.TAR_BINARY_DIST]
+    signing.required = !releaseSpec.developmentVersion && !project.findProperty( 'skipSigning' )
+    def distTasks = [ TaskNames.ZIP_SOURCE_DIST, TaskNames.TAR_SOURCE_DIST,
+                      TaskNames.ZIP_BINARY_DIST, TaskNames.TAR_BINARY_DIST ]
                      .collect { taskName -> project.tasks.getByName( taskName ) }
     distTasks.each { distTask ->
       distTask.finalizedBy signing.sign( distTask )
     }
-    project.tasks.withType(Sign) { Sign task ->
-      task.enabled = !releaseSpec.developmentVersion
+    project.tasks.withType( Sign ) { Sign task ->
+      task.enabled = !releaseSpec.developmentVersion && !project.findProperty( 'skipSigning' )
       task.onlyIf { !project.findProperty( 'skipSigning' ) }
     }
   }