mangstadt / ez-vcard

A vCard parser library for Java
Other
398 stars 92 forks source link

Custom getter in VCardProperty #133

Open prrvchr opened 1 year ago

prrvchr commented 1 year ago

I am trying to retrieve all the values by calling a custom method on a VCardProperty. (Address, Email, Categories...) I'm not a Java specialist, but I can't manage to do this without modifying the VCardProperty class. Thank you for your help.

mangstadt commented 1 year ago

Not quite sure what you're trying to accomplish. The VCard.toString() method will generate a string that displays the contents of each property object.

VCard vcard = new VCard();
vcard.setFormattedName("John Doe");
Address adr = new Address();
adr.setStreetAddress("123 Main St");
adr.setLocality("New York");
adr.setRegion("NY");
adr.setPostalCode("12345");
vcard.addAddress(adr);
System.out.println(vcard.toString());

Prints:

version=3.0
ezvcard.property.FormattedName [ group=null | parameters={} | value=John Doe ]
ezvcard.property.Address [ group=null | parameters={} | poBoxes=[] | extendedAddresses=[] | streetAddresses=[123 Main St] | localities=[New York] | regions=[NY] | postalCodes=[12345] | countries=[] ]
prrvchr commented 1 year ago

Hi mangstadt,

In fact I am trying to import cards into a database: To complete this task I need:

And this for each value of each property, independently of each other...

If I have the possibility to use a customized getter here is the code I get to import:

What will the code look like if I don't have a custom getter? I'm surprised that I'm the first to claim this....

prrvchr commented 1 year ago

I would like to add that this mode of use has the advantage of separating the processing of data (class Address, Email...) from the import logic (global processing). It makes it possible to add processing of new properties without having to modify the import logic...

EDIT: And this is important if i want the user to be able to choose which vCard properties he wants to import

mangstadt commented 1 year ago

You could serialize the vCard using Ezvcard.write() and store that in the database. ez-vcard is pretty good about round-tripping.

prrvchr commented 1 year ago

I need to be more specific about the purpose. In fact, this is part of a LibreOffice extension allowing mass mailing by email with your vCard address book.

This extension vCardOOo has some particularities:

I already have an extension that does exactly the same thing but with Google contacts: gContactOOo And I'm about to finish the one for Microsoft Contact: mContactOOo

All these extensions are written in Python except the parsing part for vCardOOo where I use ez-vcard which is the best API on vCard. ;-)

So I admit that my need is really specific, but if I want to be able to follow my specifications I will just use my modified version of ez-vcard (all my jar libraries are embedded in the extension oxt files)

mangstadt commented 1 year ago

Using sub-classes can be problematic. I might do something like this instead:

public Map<String, String> getPropertiesValue(VCardProperty property) {
  if (property instanceof Address) {
    return getPropertiesValue((Address)property);
  }
  if (property instanceof Categories) {
    return getPropertiesValue((Categories)property);
  }
  //etc
}

public Map<String, String> getPropertiesValue(Address property) {
  Map<String, String> values = new LinkedHashMap<>();
  if (getPoBox() != null) values.put("poBox", getPoBox());
  //...
  return values;
}
prrvchr commented 1 year ago

Can you confirm that if I follow your recommendations then it is no longer necessary to modify the VCardProperty class, but only the Address, Email, etc. subclasses?

In the implementation of my class Address which extends the class ezvcard.property.Address what are the methods that must be implemented?

Thank you for these hints.

mangstadt commented 1 year ago

If your goal is to convert each vCard property object (Address, Categories, etc) to a Map<String,String> object, then you shouldn't need to subclass anything! For example:

VCard vcard = ...
for (VCardProperty property : vcard.getProperties()) {
  Map<String,String> values = getPropertiesValue(property);
}
prrvchr commented 1 year ago

Yes in fact I am looking to have a single method whatever the property to obtain 3 things: