diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e526b7..5a1b7ea 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased There are currently no unreleased changes. +## [0.6.0](https://github.com/marcospassos/java-php-serializer/releases/tag/0.6.0) (2018-02-28) + +### Changed + +- Introduce adapter for `Long` type as discussed in [#2](https://github.com/marcospassos/java-php-serializer/issues/2). +- Fix missing builtin adapters reported in [#2](https://github.com/marcospassos/java-php-serializer/issues/2). +- Add support for string encoding, fixing cases where strings are badly encoded, as reported in [#3](https://github.com/marcospassos/java-php-serializer/issues/3). + ## [0.5.2](https://github.com/marcospassos/java-php-serializer/releases/tag/0.5.2) (2017-07-12) ### Changed diff --git a/README.md b/README.md index c54fdaf..d3d06a0 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ to the `dependencies` section of its `pom.xml` file: com.marcospassos phpserializer - 0.5.2 + 0.6.0 ``` @@ -82,8 +82,9 @@ Serializer serializer = new SerializerBuilder() // Sets the naming strategy to convert the name of classes // and fields from Java to PHP (default: PsrNamingStrategy) .setNamingStrategy(new MyCustomNamingStrategy()) - // Registers all builtin adapters (default: all built-in adapters) - .registerBuiltinAdapters() + // Registers all builtin adapters, using UTF-8 for encoding strings + // (default: all built-in adapters, UTF-8 charset) + .registerBuiltinAdapters(Charset.forName("UTF-8")) // Register a custom type adapter .registerAdapter(CustomObject.class, new CustomObjectAdapter()) // Creates the serialized based on the given configuration @@ -206,7 +207,7 @@ marcos@marcospassos.com instead of using the issue tracker. All contents of this package are licensed under the [MIT license](LICENSE). ``` -Copyright (c) 2017 Marcos Passos +Copyright (c) 2018 Marcos Passos Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -227,8 +228,8 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` -[maven-central-badge]: https://img.shields.io/badge/maven%20central-v0.5.2-blue.svg -[maven-central-latest]: http://search.maven.org/#artifactdetails%7Ccom.marcospassos%7Cphpserializer%7C0.5.2%7Cjar +[maven-central-badge]: https://img.shields.io/badge/maven%20central-v0.6.0-blue.svg +[maven-central-latest]: http://search.maven.org/#artifactdetails%7Ccom.marcospassos%7Cphpserializer%7C0.6.0%7Cjar [coverall-status]: https://coveralls.io/github/marcospassos/java-php-serializer [coverall-badge]: https://coveralls.io/repos/github/marcospassos/java-php-serializer/badge.svg [travis-badge]: https://travis-ci.org/marcospassos/java-php-serializer.svg?branch=master @@ -243,4 +244,4 @@ DEALINGS IN THE SOFTWARE. [issue-tracker]: https://github.com/marcospassos/java-php-serializer/issues [repository]: https://github.com/marcospassos/java-php-serializer [releases-page]: https://github.com/marcospassos/java-php-serializer/releases -[latest-release]: https://github.com/marcospassos/java-php-serializer/releases/tag/0.5.2 +[latest-release]: https://github.com/marcospassos/java-php-serializer/releases/tag/0.6.0 diff --git a/pom.xml b/pom.xml index 5c34001..7247aa7 100755 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.marcospassos phpserializer - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT jar Java PHP Serializer diff --git a/src/main/java/com/marcospassos/phpserializer/SerializerBuilder.java b/src/main/java/com/marcospassos/phpserializer/SerializerBuilder.java index 215b618..ac226a6 100755 --- a/src/main/java/com/marcospassos/phpserializer/SerializerBuilder.java +++ b/src/main/java/com/marcospassos/phpserializer/SerializerBuilder.java @@ -1,5 +1,6 @@ package com.marcospassos.phpserializer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -9,6 +10,8 @@ import com.marcospassos.phpserializer.adapter.BooleanAdapter; import com.marcospassos.phpserializer.adapter.CollectionAdapter; import com.marcospassos.phpserializer.adapter.IntegerAdapter; +import com.marcospassos.phpserializer.adapter.LongAdapter; +import com.marcospassos.phpserializer.adapter.MapAdapter; import com.marcospassos.phpserializer.adapter.ObjectAdapter; import com.marcospassos.phpserializer.adapter.ReferableObjectAdapter; import com.marcospassos.phpserializer.adapter.StringAdapter; @@ -149,9 +152,23 @@ public SerializerBuilder registerAdapter(Class type, TypeAdapter adapter) /** * Registers all builtin adapters. * + * Strings are serialized in UTF-8 by default. + * * @return The current builder. */ public SerializerBuilder registerBuiltinAdapters() + { + return registerBuiltinAdapters(Charset.forName("UTF-8")); + } + + /** + * Registers all builtin adapters. + * + * @param charset The default charset used to serialize strings. + * + * @return The current builder. + */ + public SerializerBuilder registerBuiltinAdapters(Charset charset) { ArrayAdapter arrayAdapter = new ArrayAdapter(); @@ -164,10 +181,14 @@ public SerializerBuilder registerBuiltinAdapters() registerAdapter(double[].class, arrayAdapter); registerAdapter(char[].class, arrayAdapter); registerAdapter(short[].class, arrayAdapter); + + registerAdapter(Map.class, new MapAdapter()); registerAdapter(Collection.class, new CollectionAdapter()); registerAdapter(Boolean.class, new BooleanAdapter()); + registerAdapter(Double.class, new IntegerAdapter()); registerAdapter(Integer.class, new IntegerAdapter()); - registerAdapter(String.class, new StringAdapter()); + registerAdapter(Long.class, new LongAdapter()); + registerAdapter(String.class, new StringAdapter(charset)); registerAdapter(Object.class, new ReferableObjectAdapter<>( new ObjectAdapter<>() )); diff --git a/src/main/java/com/marcospassos/phpserializer/Writer.java b/src/main/java/com/marcospassos/phpserializer/Writer.java index ad7864f..872e04f 100755 --- a/src/main/java/com/marcospassos/phpserializer/Writer.java +++ b/src/main/java/com/marcospassos/phpserializer/Writer.java @@ -2,6 +2,7 @@ package com.marcospassos.phpserializer; import java.lang.reflect.Modifier; +import java.nio.charset.Charset; import com.marcospassos.phpserializer.state.FinishedState; import com.marcospassos.phpserializer.state.WritingValueState; @@ -246,11 +247,26 @@ public void writeNull() * @param value The value. */ public void writeString(String value) + { + writeString(value, Charset.forName("UTF-8")); + } + + /** + * Writes a string in the specified charset to the buffer. + * + * @param value The value. + * @param charset The charset to be used to serialize the value. + */ + public void writeString(String value, Charset charset) { setState(state.value()); + byte[] bytes = value.getBytes(charset); + + value = new String(bytes, charset); + buffer.append("s:"); - buffer.append(value.length()); + buffer.append(bytes.length); buffer.append(":\""); buffer.append(value); buffer.append("\";"); @@ -284,6 +300,20 @@ public void writeInteger(Integer value) buffer.append(';'); } + /** + * Writes an long value to the buffer. + * + * @param value The value. + */ + public void writeInteger(Long value) + { + setState(state.value()); + + buffer.append("i:"); + buffer.append(value); + buffer.append(';'); + } + /** * Writes a float value to the buffer. * diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/ArrayAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/ArrayAdapter.java index db4d676..e55fb51 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/ArrayAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/ArrayAdapter.java @@ -6,7 +6,7 @@ import com.marcospassos.phpserializer.Writer; /** - * Adapter for handling arrays. + * Adapter for {@code Array} type. * * @param The type of values in the list. * diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/BooleanAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/BooleanAdapter.java index f5b347f..bc476c6 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/BooleanAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/BooleanAdapter.java @@ -5,7 +5,7 @@ import com.marcospassos.phpserializer.Writer; /** - * Adapter for boolean values. + * Adapter for {@code Boolean} type. * * @author Marcos Passos * @since 1.0 diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/CollectionAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/CollectionAdapter.java index a34eee1..71a32a7 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/CollectionAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/CollectionAdapter.java @@ -6,7 +6,7 @@ import com.marcospassos.phpserializer.Writer; /** - * Adapter for handling collections. + * Adapter for {@code Collection} type. * * @param The type of values in the collection. * diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/DoubleAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/DoubleAdapter.java index c458045..196643e 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/DoubleAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/DoubleAdapter.java @@ -5,7 +5,7 @@ import com.marcospassos.phpserializer.Writer; /** - * Adapter for double values. + * Adapter for {@code Double} type. * * @author Marcos Passos * @since 1.0 diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/IntegerAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/IntegerAdapter.java index 5f09539..5d7eabf 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/IntegerAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/IntegerAdapter.java @@ -5,7 +5,7 @@ import com.marcospassos.phpserializer.Writer; /** - * Adapter for boolean values. + * Adapter for {@code Integer} values. * * @author Marcos Passos * @since 1.0 diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/LongAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/LongAdapter.java new file mode 100755 index 0000000..ff8f169 --- /dev/null +++ b/src/main/java/com/marcospassos/phpserializer/adapter/LongAdapter.java @@ -0,0 +1,20 @@ +package com.marcospassos.phpserializer.adapter; + +import com.marcospassos.phpserializer.Context; +import com.marcospassos.phpserializer.TypeAdapter; +import com.marcospassos.phpserializer.Writer; + +/** + * Adapter for {@code Long} values. + * + * @author Marcos Passos + * @since 1.0 + */ +public class LongAdapter implements TypeAdapter +{ + @Override + public void write(Long value, Writer writer, Context context) + { + writer.writeInteger(value); + } +} diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/MapAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/MapAdapter.java index ec0317d..90fa259 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/MapAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/MapAdapter.java @@ -6,7 +6,7 @@ import com.marcospassos.phpserializer.Writer; /** - * Adapter for handling maps. + * Adapter for {@code Map} type. * * @param the type of keys maintained by the map. * @param the type of mapped values. diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/ObjectAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/ObjectAdapter.java index 352dda1..32e20e8 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/ObjectAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/ObjectAdapter.java @@ -11,7 +11,7 @@ import com.marcospassos.phpserializer.util.ReflectionUtils; /** - * Adapter for string values. + * Base adapter for {@code Object} type. * * @author Marcos Passos * @since 1.0 diff --git a/src/main/java/com/marcospassos/phpserializer/adapter/StringAdapter.java b/src/main/java/com/marcospassos/phpserializer/adapter/StringAdapter.java index 0543bbd..b0bad4a 100755 --- a/src/main/java/com/marcospassos/phpserializer/adapter/StringAdapter.java +++ b/src/main/java/com/marcospassos/phpserializer/adapter/StringAdapter.java @@ -1,20 +1,42 @@ package com.marcospassos.phpserializer.adapter; +import java.nio.charset.Charset; import com.marcospassos.phpserializer.Context; import com.marcospassos.phpserializer.TypeAdapter; import com.marcospassos.phpserializer.Writer; /** - * Adapter for handling strings. + * Adapter for string type. * * @author Marcos Passos * @since 1.0 */ public class StringAdapter implements TypeAdapter { + /** + * The charset. + */ + private Charset charset; + + /** + * Creates a adapter for strings encoded in UTF-8. + */ + public StringAdapter() { + this(Charset.forName("UTF-8")); + } + + /** + * Creates a adapter for strings encoded with the specified charset. + * + * @param charset + */ + public StringAdapter(Charset charset) { + this.charset = charset; + } + @Override public void write(String value, Writer writer, Context context) { - writer.writeString(value); + writer.writeString(value, this.charset); } } diff --git a/src/test/java/com/marcospassos/phpserializer/SerializerBuilderTest.java b/src/test/java/com/marcospassos/phpserializer/SerializerBuilderTest.java index b80b418..56dcf7b 100755 --- a/src/test/java/com/marcospassos/phpserializer/SerializerBuilderTest.java +++ b/src/test/java/com/marcospassos/phpserializer/SerializerBuilderTest.java @@ -1,6 +1,7 @@ package com.marcospassos.phpserializer; import java.lang.reflect.Field; +import java.nio.charset.Charset; import java.util.Map; import com.marcospassos.phpserializer.exclusion.DisjunctionExclusionStrategy; import com.marcospassos.phpserializer.exclusion.NoExclusionStrategy; @@ -14,6 +15,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; /** @@ -177,4 +179,63 @@ public void builderRegistersBuiltinAdaptersIfNoAdapterIsRegistered() assertFalse(adapters.isEmpty()); } + + @Test + public void builderRegisterStringAdapterUsingUtf8CharsetByDefault() throws Exception + { + SerializerFactory factory = mock(SerializerFactory.class); + + new SerializerBuilder(factory).build(); + + ArgumentCaptor adapterRegistryArgument = + ArgumentCaptor.forClass(AdapterRegistry.class); + + verify(factory).create( + any(NamingStrategy.class), + any(FieldExclusionStrategy.class), + adapterRegistryArgument.capture() + ); + + AdapterRegistry registry = adapterRegistryArgument.getValue(); + Writer writer = mock(Writer.class); + Context context = mock(Context.class); + + TypeAdapter adapter = registry.getAdapter(String.class); + + adapter.write("foo", writer, context); + + verify(writer).writeString("foo", Charset.forName("UTF-8")); + } + + @Test + public void builderRegisterStringAdapterUsingSpecifiedCharset() throws Exception + { + SerializerFactory factory = mock(SerializerFactory.class); + + Charset charset = Charset.forName("ISO-8859-1"); + + SerializerBuilder builder = new SerializerBuilder(factory); + builder.registerBuiltinAdapters(charset); + + builder.build(); + + ArgumentCaptor adapterRegistryArgument = + ArgumentCaptor.forClass(AdapterRegistry.class); + + verify(factory).create( + any(NamingStrategy.class), + any(FieldExclusionStrategy.class), + adapterRegistryArgument.capture() + ); + + AdapterRegistry registry = adapterRegistryArgument.getValue(); + Writer writer = mock(Writer.class); + Context context = mock(Context.class); + + TypeAdapter adapter = registry.getAdapter(String.class); + + adapter.write("foo", writer, context); + + verify(writer).writeString("foo", charset); + } } \ No newline at end of file diff --git a/src/test/java/com/marcospassos/phpserializer/SerializerTest.java b/src/test/java/com/marcospassos/phpserializer/SerializerTest.java index abe2386..b0f382f 100755 --- a/src/test/java/com/marcospassos/phpserializer/SerializerTest.java +++ b/src/test/java/com/marcospassos/phpserializer/SerializerTest.java @@ -1,6 +1,10 @@ package com.marcospassos.phpserializer; +import java.util.HashMap; +import java.util.Map; import com.marcospassos.phpserializer.adapter.IntegerAdapter; +import com.marcospassos.phpserializer.adapter.MapAdapter; +import com.marcospassos.phpserializer.adapter.StringAdapter; import com.marcospassos.phpserializer.exclusion.NoExclusionStrategy; import com.marcospassos.phpserializer.naming.PsrNamingStrategy; import org.junit.Test; @@ -27,4 +31,28 @@ public void serialize() throws Exception assertEquals("i:1;", serializer.serialize(1)); } + + @Test + public void serializeGenericAdapter() throws Exception + { + AdapterRegistry registry = new AdapterRegistry(); + registry.registerAdapter(Map.class, new MapAdapter()); + registry.registerAdapter(String.class, new StringAdapter()); + registry.registerAdapter(Integer.class, new IntegerAdapter()); + + Map map = new HashMap<>(); + + map.put(1, "foo"); + map.put(2, "bar"); + + Serializer serializer = new Serializer( + new PsrNamingStrategy(), + new NoExclusionStrategy(), + registry + ); + + String result = serializer.serialize(map); + + assertEquals("a:2:{i:1;s:3:\"foo\";i:2;s:3:\"bar\";}", result); + } } \ No newline at end of file diff --git a/src/test/java/com/marcospassos/phpserializer/WriterTest.java b/src/test/java/com/marcospassos/phpserializer/WriterTest.java index 69bb1e8..5308bc9 100755 --- a/src/test/java/com/marcospassos/phpserializer/WriterTest.java +++ b/src/test/java/com/marcospassos/phpserializer/WriterTest.java @@ -1,6 +1,7 @@ package com.marcospassos.phpserializer; import java.lang.reflect.Modifier; +import java.nio.charset.Charset; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -136,12 +137,22 @@ public void writeNull() throws Exception } @Test - public void writeString() throws Exception + public void writeStringUtf8() throws Exception { Writer writer = new Writer(); - writer.writeString("foo"); + writer.writeString("Informations générales"); - assertEquals("s:3:\"foo\";", writer.getResult()); + assertEquals("s:24:\"Informations générales\";", writer.getResult()); + } + + @Test + public void writeStringIsoCharset() throws Exception + { + Writer writer = new Writer(); + Charset charset = Charset.forName("ISO-8859-1"); + writer.writeString("Informations générales", charset); + + assertEquals("s:22:\"Informations générales\";", writer.getResult()); } @Test @@ -189,6 +200,15 @@ public void writeInteger() throws Exception assertEquals("i:1;", writer.getResult()); } + @Test + public void writeLong() throws Exception + { + Writer writer = new Writer(); + writer.writeInteger(1L); + + assertEquals("i:1;", writer.getResult()); + } + @Test public void writeFloat() throws Exception { diff --git a/src/test/java/com/marcospassos/phpserializer/adapter/LongAdapterTest.java b/src/test/java/com/marcospassos/phpserializer/adapter/LongAdapterTest.java new file mode 100755 index 0000000..40901e2 --- /dev/null +++ b/src/test/java/com/marcospassos/phpserializer/adapter/LongAdapterTest.java @@ -0,0 +1,30 @@ +package com.marcospassos.phpserializer.adapter; + +import com.marcospassos.phpserializer.Context; +import com.marcospassos.phpserializer.Writer; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +/** + * @author Marcos Passos + * @since 1.0 + */ +public class LongAdapterTest +{ + @Test + public void write() throws Exception + { + LongAdapter adapter = new LongAdapter(); + Writer writer = mock(Writer.class); + Context context = mock(Context.class); + + adapter.write(10L, writer, context); + + verify(writer).writeInteger(10L); + + verifyNoMoreInteractions(writer); + } +} \ No newline at end of file diff --git a/src/test/java/com/marcospassos/phpserializer/adapter/StringAdapterTest.java b/src/test/java/com/marcospassos/phpserializer/adapter/StringAdapterTest.java index 988cdfe..aa3b0e6 100755 --- a/src/test/java/com/marcospassos/phpserializer/adapter/StringAdapterTest.java +++ b/src/test/java/com/marcospassos/phpserializer/adapter/StringAdapterTest.java @@ -1,5 +1,6 @@ package com.marcospassos.phpserializer.adapter; +import java.nio.charset.Charset; import com.marcospassos.phpserializer.Context; import com.marcospassos.phpserializer.Writer; import org.junit.Test; @@ -15,15 +16,32 @@ public class StringAdapterTest { @Test - public void write() throws Exception + public void writeUsesUtf8ByDefault() throws Exception { + Charset charset = Charset.forName("UTF-8"); + StringAdapter adapter = new StringAdapter(); Writer writer = mock(Writer.class); Context context = mock(Context.class); adapter.write("foo", writer, context); - verify(writer).writeString("foo"); + verify(writer).writeString("foo", charset); + + verifyNoMoreInteractions(writer); + } + + @Test + public void writeCustomCharset() throws Exception + { + Charset charset = Charset.forName("ISO-8859-1"); + StringAdapter adapter = new StringAdapter(charset); + Writer writer = mock(Writer.class); + Context context = mock(Context.class); + + adapter.write("foo", writer, context); + + verify(writer).writeString("foo", charset); verifyNoMoreInteractions(writer); }