I would like serialize this immutable class
class CatalogueItem {
final Uri source;
final DateTime analyis;
final Period fromTo;
CatalogueItem.create(this.source, this.analyis, this.fromTo);
}
But I cannot as it is not a simple class. From the web site https://www.dartlang.org/articles/serialization/
Simple: All of the objects to be serialized are data transfer objects
(DTOs) with a default constructor.
So I have to add a default constructor - which means I have to drop the final keywords and my class is no longer immutable.
class CatalogueItem {
Uri source;
DateTime analyis;
Period fromTo;
CatalogueItem.create(this.source, this.analyis, this.fromTo);
CatalogueItem(){}
}
Is there any way around this one?
I think the default constructor is only necessary for deserialization (never used a package for (de)serialization). Serialization shouldn't need it.
The default constructor is redundant because if the deserialization package needs a default constructor it obviously attempts to create an instance using the default constructor to afterwards set the field values, which can't work with final fields.
I don't know if a serialization package supports a custom toJson() method/fromJson() constructor but I think this would be the easiest way to go.
class CatalogueItem {
final Uri source;
final DateTime analysis;
final Period fromTo;
CatalogueItem.create(this.source, this.analysis, this.fromTo);
factory CatalogueItem.fromJson(Map json) {
return new CatalogueItem.create(
json['source'] == null ? null : Uri.parse(json['source']),
json['analysis'] == null ? null : DateTime.parse(json['analysis'])),
json['fromTo'] == null ? null : new Period.fromJson(json['fromTo']));
}
Map toJson() {
return {
'source': source == null ? null : '$source',
'analysis': analysis == null ? null : '$analysis',
'fromTo': fromTo == null ? null : fromTo.toJson();
}
}
https://github.com/google/built_value.dart may do what you want -- it is specifically for creating immutable classes and serializing them.
Note that this requires a slightly different form for the class. This is to allow built_value to generate an implementation for you, and serializers.
abstract class CatalogueItem
implements Built<CatalogueItem, CatalogueItemBuilder> {
static Serializer<CatalogueItem> get serializer
=> _$catalogueItemSerializer;
Uri get source;
DateTime get analyis;
Period get fromTo;
factory CatalogueItem([updates(CatalogueItemBuilder b)]) =
_$CatalogueItem;
CatalogueItem._();
}
The generated implementation is immutable (uses final), and also provides operator==, hashCode and toString.
More detailed example: https://github.com/google/built_value.dart/blob/master/example/lib/example.dart
One option is to read further in the article and use the serialization package, which does handle such cases.
Related
I want to serialize FAIL object via Jackson:
interface OptionalResult<out ResultType : Any> {
val data: ResultType?
object FAIL : OptionalResult<Nothing> {
override val data: Nothing? = null
}
}
What I get is {} but I expect to receive {"data": null}.
How can I fix my object?
By the way, the following object is serialized properly:
object FAIL : OptionalResult<Int> {
override val data: Int? = null
}
Technical problem is that Jackson determines that indicator that would normally indicate existence of a property (public or annotated setter) will be filtered out, as getter is seen as public void getData() that returns nothing.
Filtering is done at low level processing, along with removal of static methods, methods that are neither annotated nor follow naming convention and so on.
It might be possible to improve upon this detection since there is actual difference between void and Void (similar to primitive/Wrapper difference).
But this is the first time such usage has been reported.
One thing that you could try which may (or might not) help: add #JsonProperty for val data. It could help if filtering is only done for non-annotated accessors.
I'm converting a Java project into Kotlin. I've converted a User object into Kotlin and when I run the existing JUnit tests in Java I'm getting a error between two instances of the Kotlin User object.
User.kt:
data class User (
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
var id: Long? = null,
...
)
TestUtil.java
import static org.assertj.core.api.Assertions.assertThat;
public class TestUtil {
public static void equalsVerifier(Class clazz) throws Exception {
Object domainObject1 = clazz.getConstructor().newInstance();
// Test with an instance of the same class
Object domainObject2 = clazz.getConstructor().newInstance();
assertThat(domainObject1).isNotEqualTo(domainObject2);
}
}
The assertThat(domainObject1).isNotEqualTo(domainObject2) test fails, as I believe in Java comparison is not done correctly on the Kotlin class. If I run this through a debugger, I can see that domainObject1 and domainObject2 are different instances.
Is it possible to get this test case to pass? The same test case is used for other Java classes, so it has to work for both Java and Kotlin classes.
The isNotEqualTo calls equals. The Kotlin class implements correct equals method for data class. So domainObject1.equals(domainObject2) is true. This behavior is correct.
just look at the AssertJ document:
isNotSameAs(Object other):
Verifies that the actual value is not the same as the given one,
ie using == comparison.
I think you should try:
assertThat(domainObject1).isNotSameAs(domainObject2);
In Kotlin, equals() is generated automatically for data class to check for equality of the properties.
Quote from "Kotlin in Action":
The generated equals() method checks that the values of all the properties are equal. ... Note that properties that aren’t declared in the primary constructor don’t take part in the equality checks and hashcode calculation.
If you want to pass the test case without modifying it, you may override equals() of your data class to check for referential equality.
override fun equals(other: Any?) = this === other
Note that it may affect your other code, if there is any function which relies on structural equality of your data class. So, I suggest that you refer to #shawn's answer to change your test case instead.
If I am modeling my value objects using Kotlin data classes what is the best way to handle validation. Seems like the init block is the only logical place since it executes after the primary constructor.
data class EmailAddress(val address: String) {
init {
if (address.isEmpty() || !address.matches(Regex("^[a-zA-Z0-9]+#[a-zA-Z0-9]+(.[a-zA-Z]{2,})$"))) {
throw IllegalArgumentException("${address} is not a valid email address")
}
}
}
Using JSR-303 Example
The downside to this is it requires load time weaving
#Configurable
data class EmailAddress(#Email val address: String) {
#Autowired
lateinit var validator: Validator
init {
validator.validate(this)
}
}
It seems unreasonable to me to have object creation validation anywhere else but in the class constructor. This is the place responsible for the creation, so that is the place where the rules which define what is and isn't a valid instance should be. From a maintenance perspective it also makes sense to me as it would be the place where I would look for such rules if I had to guess.
I did make a comment, but I thought I would share my approach to validation instead.
First, I think it is a mistake to perform validation on instantiation. This will make the boundary between deserialization and handing over to your controllers messy. Also, to me, if you are sticking to a clean architecture, validation is part of your core logic, and you should ensure with tests on your core logic that it is happening.
So, to let me tackle this how I wish, I first define my own core validation api. Pure kotlin. No frameworks or libraries. Keep it clean.
interface Validatable {
/**
* #throws [ValidationErrorException]
*/
fun validate()
}
class ValidationErrorException(
val errors: List<ValidationError>
) : Exception() {
/***
* Convenience method for getting a data object from the Exception.
*/
fun toValidationErrors() = ValidationErrors(errors)
}
/**
* Data object to represent the data of an Exception. Convenient for serialization.
*/
data class ValidationErrors(
val errors : List<ValidationError>
)
data class ValidationError(
val path: String,
val message: String
)
Then I have a framework specific implementations. For example a javax.validation.Validation implementation:
open class ValidatableJavax : Validatable {
companion object {
val validator = Validation.buildDefaultValidatorFactory().validator!!
}
override fun validate() {
val violations = validator.validate(this)
val errors = violations.map {
ValidationError(it.propertyPath.toString(), it.message)
}.toMutableList()
if (errors.isNotEmpty()) {
throw ValidationErrorException(errors = errors)
}
}
}
The only problem with this, is that the javax annotations don't play so well with kotlin data objects - but here is an example of a class with validation:
import javax.validation.constraints.Positive
class MyObject(
myNumber: BigDecimal
) : ValidatableJavax() {
#get:Positive(message = "Must be positive")
val myNumber: BigDecimal = myNumber
}
Actually, it looks like that validation is not a responsibility of data classes. data tells for itself — it's used for data storage.
So if you would like to validate data class, it will make perfect sense to set #get: validation on arguments of the constructor and validate outside of data class in class, responsible for construction.
Your second option is not to use data class, just use simple class and implement whole logic in the constructor passing validator there
Also, if you use Spring Framework — you can make this class Bean with prototype scope, but chances are it will be absolutely uncomfortable to work with such kind of spaghetti-code :)
I disagree with your following statement :
Seems like the init block is the only logical place since it executes after the primary constructor.
Validation should not be done at construction time, because sometimes, you need to have intermediate steps before getting a valid object, and it does not work well with Spring MVC for example.
Maybe use a specific interface (like suggested in previous answer) with a method dedicated to executing validation.
For the validation framework, I personnaly use valiktor, as I found it a lot less cumbersome that JSR-303
I have a Serialization interface which is designed to encapsulate the differences between XML/JSON/binary serialization for my application. It looks something like this:
interface Serialization {
bool isObject();
int opApply(int delegate(string member, Serialization value) del); //iterate object
...
int toInt(); //this part is ugly, but without template member overloading, I
long toLong(); //figure out any way to apply generics here, so all basic types
... //have a toType primitive
string toString();
}
class JSONSerialization : Serialization {
private JSON json;
...
long toLong() {
enforce(json.type == JSON_TYPE.NUMBER, SerializationException.IncorrectType);
return cast(long)json.toNumber();
}
...
}
So, what I then set up is a set of templates for registering type deserializers and calling them:
...
registerTypeDeserializer!Vec3(delegate Vec3(Serialization s) {
return Vec3(s[0].toFloat, s[1].toFloat, s[2].toFloat);
});
...
auto v = parseJSON("some file").deserialize!Vec3;
...
registerTypeDeserializer!Light(delegate Light(Serialization s) {
return new Light(s["intensity"].toFloat, s["position"].deserialize!Vec3);
});
This works well for structs and simple classes, and with the new parameter identifier tuple and parameter default value tuple I should even be able to add automatic deserializer generation. However, I don't really like the inconsistency between basic and user defined types, and more importantly, complex types have to rely on global state to acquire references:
static MaterialLibrary materials;
registerTypeDeserializer!Model(delegate Model(Serialization s) {
return new Model(materials.borrow(s["material"].toString), ...);
});
That's where it really falls apart. Because I can't (without a proliferation of register deserializer functions) pass other parameters to the deserializer, I'm having difficulty avoiding ugly global factories. I've thought about eliminating the deserialize template, and requiring a deserialize function (which could accept multiple parameters) for each user defined type, but that seems like a lot of work for e.g. POD structs.
So, how can I simplify this design, and hopefully avoid tons of boilerplate deserializers, while still allowing me to inject object factories appropriately, instead of assigning them globally?
Basic types can be read using readf \ formattedRead, so you can create a wrapper function that uses this formattedRead it possible, otherwise it uses a static function from the desired type to read the value. Something like this:
auto _readFrom(T)(string s){
static if(__traits(compiles,(readf("",cast(T*)(null))))){
T result;
formattedRead(s,"%s",&result);
return result;
}else{
return T.readFrom(s);
}
}
I'm experimenting with PetaPoco to convert a table into POCOs.
In my table, I've got a column named TheEnum. The values in this column are strings that represent the following enum:
public enum MyEnum
{
Fred,
Wilma
}
PetaPoco chokes when it tries to convert the string "Fred" into a MyEnum value.
It does this in the GetConverter method, in the line:
Convert.ChangeType( src, dstType, null );
Here, src is "Fred" (a string), and dstType is typeof(MyEnum).
The exception is an InvalidCastException, saying Invalid cast from 'System.String' to 'MyEnum'
Am I missing something? Is there something I need to register first?
I've got around the problem by adding the following into the GetConverter method:
if (dstType.IsEnum && srcType == typeof(string))
{
converter = delegate( object src )
{
return Enum.Parse( dstType, (string)src ) ;
} ;
}
Obviously, I don't want to run this delegate on every row as it'll slow things down tremendously. I could register this enum and its values into a dictionary to speed things up, but it seems to me that something like this would likely already be in the product.
So, my question is, do I need to do anything special to register my enums with PetaPoco?
Update 23rd February 2012
I submitted a patch a while ago but it hasn't been pulled in yet. If you want to use it, look at the patch and merge into your own code, or get just the code from here.
I'm using 4.0.3 and PetaPoco automatically converts enums to integers and back. However, I wanted to convert my enums to strings and back. Taking advantage of Steve Dunn's EnumMapper and PetaPoco's IMapper, I came up with this. Thanks guys.
Note that it does not handle Nullable<TEnum> or null values in the DB. To use it, set PetaPoco.Database.Mapper = new MyMapper();
class MyMapper : PetaPoco.IMapper
{
static EnumMapper enumMapper = new EnumMapper();
public void GetTableInfo(Type t, PetaPoco.TableInfo ti)
{
// pass-through implementation
}
public bool MapPropertyToColumn(System.Reflection.PropertyInfo pi, ref string columnName, ref bool resultColumn)
{
// pass-through implementation
return true;
}
public Func<object, object> GetFromDbConverter(System.Reflection.PropertyInfo pi, Type SourceType)
{
if (pi.PropertyType.IsEnum)
{
return dbObj =>
{
string dbString = dbObj.ToString();
return enumMapper.EnumFromString(pi.PropertyType, dbString);
};
}
return null;
}
public Func<object, object> GetToDbConverter(Type SourceType)
{
if (SourceType.IsEnum)
{
return enumVal =>
{
string enumString = enumMapper.StringFromEnum(enumVal);
return enumString;
};
}
return null;
}
}
You're right, handling enums is not built into PetaPoco and usually I just suggest doing exactly what you've done.
Note that this won't slow things down for requests that don't use the enum type. PetaPoco generates code to map responses to pocos so the delegate will only be called when really needed. In other words, the GetConverter will only be called the first time a particular poco type is used, and the delegate will only be called when an enum needs conversion. Not sure on the speed of Enum.Parse, but yes you could cache in a dictionary if it's too slow.
If you are using PetaPoco's T4 generation and you want enums in your generated type, you can use the PropertyType override in Database.tt:
tables["App"]["Type"].PropertyType = "Full.Namespace.To.AppType";
I you want to store the value of the enum instead of the index number (1,2,4 for example) you can locate the update function in PetaPoco class because the code is "managed" etc, when you add it as nuget package it will store the .cs file to your project. If we would have the enum variable Color = {red, yellow, blue}
Instead of:
// Store the parameter in the command
AddParam(cmd, pc.GetValue(poco), pc.PropertyInfo);
change to:
//enum?
if (i.Value.PropertyInfo.PropertyType.IsEnum)
{
AddParam(cmd, i.Value.GetValue(poco).ToString(), i.Value.PropertyInfo);
}
else
{
// Store the parameter in the command
AddParam(cmd, i.Value.GetValue(poco), i.Value.PropertyInfo);
}
It would store "yellow" instead of 2