How to serialize a custom class with YamlDotNet - yamldotnet

I'm trying to serialize a custom class with YamlDotNet library.
Here is my class:
public class Person
{
string firstName;
string lastName;
public Person(string first, string last)
{
firstName = first;
lastName = last;
}
}
And here is how I tried to serialize it:
StreamWriter streamWriter = new StreamWriter("Test.txt");
Person person = new Person("toto", "titi");
Serializer serializer = new Serializer();
serializer.Serialize(streamWriter, person);
But in my output file, I only have this : { }
What did I forget to do to serialize my class?

The default behavior of YamlDotNet is to serialize public properties and to ignore fields. The easiest fix is to replace the public fields with automatic properties:
public class Person
{
public string FirstName { get; private set; }
public string LastName { get; private set; }
public Person(string first, string last)
{
FirstName = first;
LastName = last;
}
}
You could alter the behavior of YamlDotNet to serialize private fields relatively easily, but I do not recommend that.

Related

Azure table entity model design

In most examples of table entity models I see something like:
public class CustomerEntity : TableEntity
{
public CustomerEntity(string lastName, string firstName)
{
this.PartitionKey = lastName;
this.RowKey = firstName;
}
public CustomerEntity() { }
public string Email { get; set; }
public string PhoneNumber { get; set; }
}
As we see here lastname and firstname used as partition key and row key accordingly. So later after saving and retrieving an entity I can access those info from PartitionKey and RowKey properties. But what if I want to send this model to client side later as json, I suppose PartitionKey and RowKey of TableEntity base class would not be serialized. So if i add LastName and FirstName as properties to model, then unnecessary data duplication will occur in storage. What is the best way avoid data duplication in storage and in the same time have an access to lastname and firstname after model been serialized.
You can always use a getter method on your class to avoid confusion:
public class CustomerEntity : TableEntity
{
public CustomerEntity(string lastName, string firstName)
{
this.PartitionKey = lastName;
this.RowKey = firstName;
}
public CustomerEntity() { }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string FirstName { get { return this.RowKey; } }
public string LastName { get { return this.PartitionKey; } }
}
Or, you could map the data to an anonymous object in your API and return that via JSON:
var customerJson = new
{
Firstname = customer.RowKey,
LastName = customer. PartitionKey,
customer.Email,
customer.PhoneNumber
};
return JsonConvert.SerializeObject(customerJson);

Spring-data-cassandra's CassandraTemplate returns String, not a specified Object, when run queryForObject function.

I've been going through the Spring Data Cassandra documentation (http://docs.spring.io/spring-data/cassandra/docs/1.0.1.RELEASE/reference/html/cassandra.core.html)
Basically, with proper annotation, I hoped the CassandraTemplate maps a row to a POJO object, but it didn't work as I expected.
For the call,
cassandraOps.queryForObject(s, Person.class)
I received an error as following:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to Person
Anything that I'm missing? Following is the same copy and paste from the doc above.
Person Class looks like:
#Table
public class Person {
#PrimaryKey
private String id;
private String name;
private int age;
public Person(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
#Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
and the application class looks like...:
public class CassandraApp {
private static final Logger LOG = LoggerFactory.getLogger(CassandraApp.class);
private static Cluster cluster;
private static Session session;
public static void main(String[] args) {
try {
cluster = Cluster.builder().addContactPoints(InetAddress.getLocalHost()).build();
session = cluster.connect("mykeyspace");
CassandraOperations cassandraOps = new CassandraTemplate(session);
cassandraOps.insert(new Person("1234567890", "David", 40));
Select s = QueryBuilder.select().from("person");
s.where(QueryBuilder.eq("id", "1234567890"));
LOG.info(cassandraOps.queryForObject(s, Person.class).getId());
cassandraOps.truncate("person");
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
CassandraTemplate's queryForObject(String,Class) is not meant for arbitrary object mapping. It is modeled after JdbcTemplate's queryForObject(String,Class) method. It's intended to take types that the Cassandra driver can convert directly.
To convert arbitrary application-defined classes, use queryForObject(String,RowMapper<T>) or one of its overloads. CqlTemplate doesn't know how to map arbitrary classes; you have to supply the RowMapper<T> implementation for your class T.
you can do it like this way:-
String myQuery = "select * from person where id=1234567890";
Person personObj = cassandraOperations.selectOne(myQuery, Person.class);
<<
For all
List<Person> personListObj = cassandraOperations.select(myQuery, Person.class); >>
this work for me using cassandraTemplete object perfectly... didn't try for cassandraOperation.
also you might need #Column(value = "your_columnName_in_DB") if your pojo class's variable name is different
like
#Column(value = "name")
private String userName;
#Column(value = "age")
private int userAge;
revert here if its work?
Also can you help me pass dynamic value to that myQuery string.. using object[] same like prepareStatment in SQL
thanks.

Contra variance with interfaces

I have an interface iExportColumn and a class ExportColumn implementing the interfce. ExportColumnCollection class should be generic for all the classes that implements IExportColumn interface.
public interface IExportColumn
{
string Header { get; set; }
string ColumnName { get; set; }
}
public class ExportColumn : IExportColumn
{
public ExportColumn(){}
public string Header { get; set; }
public string ColumnName { get; set; }
}
public class ExportColumnCollection<T> where T: IExportColumn
{
private List<T> cols;
public ExportColumnCollection (List<T> c)
{
cols = c;
}
public T Columninfo (string colname)
{
}
.....
}
I am getting run time error saying could not load type ExportColumnCollection.
I am looking for something to achieve somthing like
List<IExportColumn> = new List<ExportColumn>();
I have two classes implementing the interfaces IExportColumn and I need to hold a GenericCollection to handle List
The proper usage for your class would be:
List<IExportColumn> list= new List<IExportColumn>();
// you may add to the collection any class which implements IExportColumn
list.Add(new ExportColumn1() { ColumnName = "Id" });
list.Add(new ExportColumn2() { ColumnName = "Value" });
ExportColumnCollection<IExportColumn> collection = new
ExportColumnCollection<IExportColumn>(list);
var colInfo = collection.ColumnInfo("Id");

servicestack serializes to empty json string

I am having a strange issue with ServiceStack (SS). The entity I pass to the method is always serialized to empty json string by SS. So s is always "{}". I debug and see that the entity is a hydrated instance with properties with values.
Any ideas why this is the case?
public virtual void Serialize<TEntity>(TEntity entity, Stream stream)
{
// s is always {}
var s = JsonSerializer.SerializeToString(entity);
// rest is not important at this point...
s = JsvFormatter.Format(s);
using (var writer = new StreamWriter(stream))
{
writer.Write(s);
}
}
I am editing the question show exactly what the passed in (VolumeCreated) entity is.
public class VolumeEvent : IEvent<VolumeID>
{
public VolumeEvent(VolumeID identity)
{
Identity = identity;
}
#region Implementation of IEvent<out VolumeIdentity>
public VolumeID Identity { get; private set; }
#endregion
}
public class VolumeCreated : VolumeEvent
{
public DateTime PublishDate { get; set; }
public string Title { get; set; }
public VolumeCreated(VolumeID identity, string title, DateTime publishDate)
: base(identity)
{
Title = title;
PublishDate = publishDate;
}
}
ServiceStack serializes only serializes public properties.

AutoMapper mapping properties with private setters

Is it possible to assign properties with private setters using AutoMapper?
AutoMapper allows now (I am not sure, since when) to map properties with private setters. It is using reflection for creating objects.
Example classes:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class PersonDto
{
public string Fullname { get; private set; }
}
And mapping:
AutoMapper.Mapper.CreateMap<Person, PersonDto>()
.ForMember(dest => dest.Fullname, conf => conf.MapFrom(src => src.Name + " " + src.Surname));
var p = new Person()
{
Name = "John",
Surname = "Doe"
};
var pDto = AutoMapper.Mapper.Map<PersonDto>(p);
AutoMapper will map property with private setter with no problem. If you want to force encapsulation, you need to use IgnoreAllPropertiesWithAnInaccessibleSetter. With this option, all private properties (and other inaccessible) will be ignored.
AutoMapper.Mapper.CreateMap<Person, PersonDto>()
.ForMember(dest => dest.Fullname, conf => conf.MapFrom(src => src.Name + " " + src.Surname))
.IgnoreAllPropertiesWithAnInaccessibleSetter();
The problem will emerge, if you will use Silverlight. According to MSDN: https://msdn.microsoft.com/en-us/library/stfy7tfc(v=VS.95).aspx
In Silverlight, you cannot use reflection to access private types and members.
If you set the value for this properties in the constructor like this
public class RestrictedName
{
public RestrictedName(string name)
{
Name = name;
}
public string Name { get; private set; }
}
public class OpenName
{
public string Name { get; set; }
}
then you can use ConstructUsing like this
Mapper.CreateMap<OpenName, RestrictedName>()
.ConstructUsing(s => new RestrictedName(s.Name));
which works with this code
var openName = new OpenName {Name = "a"};
var restrictedName = Mapper.Map<OpenName, RestrictedName>(openName);
Assert.AreEqual(openName.Name, restrictedName.Name);
See #600 Private/internal destination properties.
Solution:
public class PrivateInternalProfile {
protected override Configure() {
ShouldMapField = fieldInfo => true;
ShouldMapProperty = propertyInfo => true;
CreateMap<User, UserDto>(); //etc
}
}

Resources