JPA - Hibernate : Map several tables on one column of another - java

Conserider following table structure
country
=======
id
code
name_id
label
======
id
code
label_value_id
translations
=============
id
ref_id
language
value
Now I need to find a JPA mapping to map country:name_id and label:label_value_id to translations ref_id. I've been googling after the right english term to explain this situation but am coming up empty on decent hits. So the database can hold records as in this example
country
id: 1, code: BE, name_id: 30
label
id: 1, code: LABELA, label_value_id: 31
translations
id: 1, ref_id: 30, language: EN, value: BELGIUM
id: 2, ref_id: 30, language: NL, value: BELGIE
id: 3, ref_id: 31, language: EN, value: ALPHA_A
id: 4, ref_id: 31, language: NL, value: ALFA_A
In Java I have the 3 classes
Country, Label and Translation where I will have #OneToMany relations on Country and Label to Translation that both should map on ref_id but I have no idea how to write my #OneToMany code to achieve this. Any hints in the right direction would be very appreciated, a solution or manual
=====
Update 2013-03-23
As stated by Joop, using a discriminator is the sollution BUT it didn't work out of the box. I was forced to use a hibernate annotation #DiscriminatorOptions(force=true). If you don't add it , hibernate totally ignores the Discriminator in it's SQL queries when fetching the needed collections.
#Entity
#Table(name = "testtranslations")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRING)
#DiscriminatorOptions(force=true)
public class TestTranslation extends DomainObject {
/**
*
*/
private static final long serialVersionUID = -6211853644196769521L;
private long id;
private String language;
private String value;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="testtranslations_seq_gen")
#SequenceGenerator(name="testtranslations_seq_gen", sequenceName="TESTTRANSLATIONS_SEQ")
#Column(name="testtranslation_id")
public long getId() {
return id;
}
#Column(name="language", length=3, nullable=false)
public String getLanguage() {
return language;
}
#Column(name="value")
public String getValue() {
return value;
}
#Override
public void setId(long id) {
this.id = id;
}
public void setLanguage(String language) {
this.language = language;
}
public void setValue(String value) {
this.value = value;
}
}
#Entity
#Table(name = "testcountries")
public class TestCountry extends DomainObject {
/**
*
*/
private static final long serialVersionUID = -9207081478447113501L;
private long id;
private String code;
private List<NameTranslation> name;
private List<DescriptionTranslation> description;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="testcountries_seq_gen")
#SequenceGenerator(name="testcountries_seq_gen", sequenceName="TESTCOUNTRIES_SEQ")
#Column(name="country_id")
public long getId() {
return id;
}
#Column(name="iso_code", length=3, nullable=false)
public String getCode() {
return code;
}
#OneToMany(mappedBy="refId")
public List<NameTranslation> getName() {
return name;
}
#OneToMany(mappedBy="refId")
public List<DescriptionTranslation> getDescription() {
return description;
}
#Override
public void setId(long id) {
this.id = id;
}
public void setCode(String code) {
this.code = code;
}
public void setName(List<NameTranslation> name) {
this.name = name;
}
public void setDescription(List<DescriptionTranslation> description) {
this.description = description;
}
}
#Entity
#DiscriminatorValue("NAMETRANSLATION")
public class NameTranslation extends TestTranslation {
/**
*
*/
private static final long serialVersionUID = 7197732491071768673L;
private TestCountry refId;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "refId", nullable=false)
public TestCountry getRefId() {
return refId;
}
public void setRefId(TestCountry refId) {
this.refId = refId;
}
}
#Entity
#DiscriminatorValue("DESCTRANSLATION")
public class DescriptionTranslation extends TestTranslation {
/**
*
*/
private static final long serialVersionUID = -4128287237786410515L;
private TestCountry refId;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "refId", nullable=false)
public TestCountry getRefId() {
return refId;
}
public void setRefId(TestCountry refId) {
this.refId = refId;
}
}
I made the needed hibernate mappings and wrote a DbUnit test to load a TestCountry by id with following data
<TESTCOUNTRIES COUNTRY_ID="1" VERSION="0" ISO_CODE="BE" />
<TESTTRANSLATIONS TESTTRANSLATION_ID="1" VERSION="0" LANGUAGE="EN" VALUE="Belgium" REFID="1" DTYPE="NAMETRANSLATION" />
<TESTTRANSLATIONS TESTTRANSLATION_ID="2" VERSION="0" LANGUAGE="NL" VALUE="Belgie" REFID="1" DTYPE="NAMETRANSLATION" />
<TESTTRANSLATIONS TESTTRANSLATION_ID="3" VERSION="0" LANGUAGE="EN" VALUE="BelgiumDesc" REFID="1" DTYPE="DESCTRANSLATION" />
<TESTTRANSLATIONS TESTTRANSLATION_ID="4" VERSION="0" LANGUAGE="NL" VALUE="BelgieDesc" REFID="1" DTYPE="DESCTRANSLATION" />
I hope this will help other people in the future, I'm just sad there isn't a JPA sollution and I had to be forced to use a hibernate annotation.

A bit difficult as you have a foreign key for either table 1 or table 2.
There does exist a discriminator concept in JPA, for table inheritance. One then derives two tables from a common abstract table, and has different discriminator fields. An example. This works a bit differently though.
P.S. look for a better example using search keys discriminatorValue and discriminatorColumn.

Related

JOOQ + JPA entities

I'm new with JOOQ library and have one thing interesting me so much. I've implemented CRUD service on JOOQ at first and after that I've tried to avoid some duplicate code. For reach that goal I've added JPA repository and also added#Entity annotation to my generated by JOOQ class. And now I still want to use JOOQ for some cases (querying List using filter and sorting and pagination). But something went wrong and now after JOOQ makes a select request I can see nulls in my class's attributes.
I'm getting right count of entities by filter, but class's properties are null after mapping. Is that mapping wrong or I just could't use JOOQ and JPA together for this case?
My abstact class for all entities (as I said, for avoid duplicating code I've refactored some code and now use generics):
#MappedSuperclass
public abstract class AbstractServiceEntity {
private Integer id;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
My JPA class (generated by JOOQ):
/**
* This class is generated by jOOQ.
*/
#SuppressWarnings({ "all", "unchecked", "rawtypes" })
#Entity
#Table(schema = "ref", name = "account")
public class Account extends AbstractServiceEntity implements Serializable {
private static final long serialVersionUID = -162537472;
private Integer id;
private Integer transitId;
private Integer partnerId;
private String currencyCode;
private String descr;
private Long inCredit;
private Long balanceLimit;
private Long outCredit;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private Integer transitPartnerId;
public Account() {}
public Account(Account value) {
this.id = value.id;
this.transitId = value.transitId;
this.partnerId = value.partnerId;
this.currencyCode = value.currencyCode;
this.descr = value.descr;
this.inCredit = value.inCredit;
this.balanceLimit = value.balanceLimit;
this.outCredit = value.outCredit;
this.createdAt = value.createdAt;
this.updatedAt = value.updatedAt;
this.transitPartnerId = value.transitPartnerId;
}
public Account(
Integer id,
Integer transitId,
Integer partnerId,
String currencyCode,
String descr,
Long inCredit,
Long balanceLimit,
Long outCredit,
LocalDateTime createdAt,
LocalDateTime updatedAt,
Integer transitPartnerId
) {
this.id = id;
this.transitId = transitId;
this.partnerId = partnerId;
this.currencyCode = currencyCode;
this.descr = descr;
this.inCredit = inCredit;
this.balanceLimit = balanceLimit;
this.outCredit = outCredit;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
this.transitPartnerId = transitPartnerId;
}
And my method extracting entities from DB:
#Repository
#RequiredArgsConstructor
public class JooqAccountRepository {
private final DSLContext jooq;
public List<Account> findAll(Condition filterCondition, SortField[] sortFields, Integer partnerId, Integer limit, Integer offset) {
return jooq.selectFrom(ACCOUNT)
.where(ACCOUNT.PARTNER_ID.equal(partnerId))
.and(filterCondition)
.orderBy(sortFields)
.limit(limit)
.offset(offset)
.fetchInto(Account.class);
}
public Integer findAccountsCount(Integer partnerId) {
return jooq.selectCount().from(ACCOUNT)
.where(ACCOUNT.PARTNER_ID.equal(partnerId))
.fetchOne(0, Integer.class);
}
}
As a result of my searches - I've made a mistake with annotations in Account class. If you want use these frameworks together, you should use #Column on entity's properties or setting your jooq's codegen plugin in different way)
This resource was usefull for me

Extending/modifying generated entities in Hibernate

I am creating a REST api service for a mysql database. I've generated classes using IntelliJ's persistence tool. It does a pretty good job.
There are some quirks to the schema that I am working with. The users want the endpoints to be accessible by another property other than the "id" primary key column.
Ex: /object/<name property>' versus/object/`.
Here is the catch though. The schema can change. The name property is not going anywhere though so I can safely assume that will always be on the object.
I've learned that you can use Superclasses to force these generated entites to have custom properties without affecting the database schema. I dont want to make a model change in the generated entity and have that update the database table layout as it is not my database.
I have a class called Animal.
#Entity
#Table(name = "animals", schema = "xyz123", catalog = "")
public class AnimalEntity extends AnimalSuperclass {
private Integer id;
private String name;
private String description;
#Id
#Column(name = "id", nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = true, length = 80)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "description", nullable = true, length = 255)
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RoleEntity that = (RoleEntity) o;
return Objects.equals(id, that.id) &&
Objects.equals(name, that.name) &&
Objects.equals(description, that.description);
}
#Override
public int hashCode() {
return Objects.hash(id, name, description);
}
}
I have to manually add extends AnimalSuperclass. Which is fine for now. Eventually I am going to try to generate these using .xmls on runtime.
Then I have this superclass..
#MappedSuperclass
public class AnimalSuperclass implements Serializable {
private String testMessage;
private String name;
private Integer id;
#Transient
public String getTestMessage() {
return this.testMessage;
}
public void setTestMessage(String id) {
this.testMessage = testMessage;
}
}
What I want to do is force the #Id annotation to be on the name property from within the superclass. Something like this..
#MappedSuperclass
public class AnimalSuperclass implements Serializable {
private String testMessage;
private String name;
private Integer id;
#Transient
public String getTestMessage() {
return this.testMessage;
}
public void setTestMessage(String id) {
this.testMessage = testMessage;
}
#Basic
#Id
#Column(name = "name", nullable = false, length = 15)
private String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
#NaturalId
#Column(name = "id", nullable = false)
private Integer getId() {
return id;
}
private void setId(Integer id) {
this.id = id;
}
}
How do I go about doing that? Currently this throws an error when I hit the endpoint: {"cause":null,"message":"Id must be assignable to Serializable!: null"}
Java is not my first language so I am not an expert by any means. But from what I've read, its not possible to override subclass properties from the superclass. Is there a better way to approach this, maybe by using RepositoryRestConfiguration? I am using PagingAndSortingRepository to serve these entities. I cannot extend the entities and use my superclass as a child as that creates a dType property in the schema and I cannot alter the table layout.
There is no hard link between the request and your entity. In your repository you can write methods that can query the data that is brought it from the request.
For example if they are requesting a name you can do something like
Page<AnimalEntity> findByName(String name, Pageable pageable);
in your Repository. Spring will take care of the rest and then you can call this in your controller.
#Service
public class AnimalService {
#Autowired
private AnimalEntityRepository animalRepo;
public Page<AnimalEntity> findAnimal(String name) {
Page<AnimalEntity> animals = animalRepo.findByName(name, new PageRequest(1,20));
return animals;
}
}
One thing to mention is that depending on how you configured Hibernate when sending an entity back to the client and the entity is seralized you might get an failed to lazy initialize error. If that is the case your entities will have to be converted to a POJO (plain old java object) and that sent back.

ManyToMany : MappingException: Could not determine type for: java.util.List

I have some tables :
PROFIL : id_profil, ...
EXPERIENCE : id_experience, id_profil#, ...
COMPETENCE_LEVEL : id_competence_level, level, ...
One PROFIL can have lot of EXPERIENCE and lot of COMPETENCE_LEVEL.
One EXPERIENCE can have lot of COMPETENCE_LEVEL.
One COMPETENCE_LEVEL concerns lot of EXPERIENCE.
So, for me, between EXPERIENCE and COMPETENCE_LEVEL, this is a (n-p) ManyToMany relation.
I tried:
PROFIL.java:
#Entity
#Table(name="profil")
public class Profil {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_profil")
private Long idProfil;
public Profil() {
super();
}
public Long getIdProfil() {
return idProfil;
}
public void setIdProfil(Long idProfil) {
this.idProfil = idProfil;
}
#Override
public String toString() {
//[...]
}
}
EXPERIENCE.java:
#Entity
#Table(name="experience")
public class Experience {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_experience")
private Long idExperience;
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
private List<CompetenceLevel> competenceLevels;
public Experience() {
super();
idProfil = new Profil();
}
public Long getIdExperience() {
return idExperience;
}
public void setIdExperience(Long idExperience) {
this.idExperience = idExperience;
}
public Profil getIdProfil() {
return idProfil;
}
public void setIdProfil(Profil idProfil) {
this.idProfil = idProfil;
}
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "experience_competence_level", joinColumns = #JoinColumn(name = "id_experience", referencedColumnName = "id_experience"), inverseJoinColumns = #JoinColumn(name = "id_competence_level", referencedColumnName = "id_competence_level"))
public List<CompetenceLevel> getCompetenceLevels() {
return competenceLevels;
}
public void setCompetenceLevels(List<CompetenceLevel> competenceLevels) {
this.competenceLevels = competenceLevels;
}
#Override
public String toString() {
// [...]
}
}
COMPETENCE_LEVEL.java:
#Entity
#Table(name="competence_level")
public class CompetenceLevel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_competence_level")
private Long idCompetenceLevel;
#OneToOne
#JoinColumn(name="id_level")
private Level level;
#OneToOne
#JoinColumn(name="id_profil")
private Profil profil;
private List<Experience> experiences;
public CompetenceLevel() {
super();
}
public Long getIdCompetenceLevel() {
return idCompetenceLevel;
}
public void setIdCompetenceLevel(Long idCompetenceLevel) {
this.idCompetenceLevel = idCompetenceLevel;
}
public Level getLevel() {
return level;
}
public void setLevel(Level level) {
this.level = level;
}
public Profil getProfil() {
return profil;
}
public void setProfil(Profil profil) {
this.profil = profil;
}
#ManyToMany(mappedBy = "competenceLevels")
public List<Experience> getExperiences() {
return experiences;
}
public void setExperiences(List<Experience> experiences) {
this.experiences = experiences;
}
#Override
public String toString() {
// [...]
}
}
So, I have this error :
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: competence_level, for columns: [org.hibernate.mapping.Column(experiences)]
I don't understand why. I follow this tuto : https://hellokoding.com/jpa-many-to-many-relationship-mapping-example-with-spring-boot-maven-and-mysql/
Do you have an idea ? Thanks.
The reason is simply: don't mix field and method annotations in the same persistent class.
Hibernate generates an unclear error here. It is very hard to figure out the reason of the error, if you don't face it before.
In your code, you are mixing field access and property access. See this answer.
I would prefer using only one of the possibilities. I use field annotations, like you did for idProfil.
In the book "Professional Java for Web Applications" by Nicholas S. Williams (very, very good) I found this:
You should never mix JPA property annotations and JPA field
annotations in the same entity. Doing so results in unspecified
behaviour and is very likely to cause errors.
And just for clearness, I wouldn't write this
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
// better:
// private Profil profil;

Caused by: org.hibernate.QueryException: could not resolve property from inner enum class

Having this domain class and using hibernate 3.2.6 integrated with JPA under spring 3.2.4
#Entity
public class PriorityDeviceKeyword {
public enum PriorityDeviceKey {
ALL ("ALL", "ALL DEVICES"),
IOS ("IOS", "IOS"),
ANDROID ("ANDROID","ANDROID");
private final String name;
private final String id;
private PriorityDeviceKey(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
#Id
private Long id;
#Column(name = "key")
private PriorityDeviceKey key;
#ManyToMany
#JoinTable(name = "t_priority_device_set", joinColumns = #JoinColumn(name = "priority_device__id", referencedColumnName = "id"))
private List<PriorityDevice> priorityDevices;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public PriorityDeviceKey getKey() {
return key;
}
public void setKey(PriorityDeviceKey key) {
this.key = key;
}
public List<PriorityDevice> getPriorityDevices() {
return priorityDevices;
}
public void setPriorityDevices(List<PriorityDevice> priorityDevices) {
this.priorityDevices = priorityDevices;
}
}
When executing this query that I have below method in my DAO class that I execute
#Override
#SuppressWarnings("unchecked")
public Set<PriorityDevices> findPriorityAreas(PriorityDevicesKey key) {
String jpql = "from PriorityDevices as pak where pak.key.name = :keyName";
Query query = entityManager.createQuery(jpql);
query.setParameter("keyName", key.getName());
List<PriorityDevices> priorityDevices = query.getResultList();
return new HashSet<PriorityDevices>(priorityDevices);
}
I get this Exception thrown by the application:
2015-01-14 13:14:50,936 ERROR [com.controller.errors.Error500Controller] - Application thrown an exception
java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: name of: com.domain.PriorityDevicesKeyword [from com.domain.PriorityDevicesKeyword as
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:624)
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:96)
at sun.reflect.GeneratedMethodAccessor440.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
Think these changes may work for you:
#Column(name = "key")
#Enumerated(EnumType.STRING)
private PriorityAreaKey key;
and
String jpql = "from PriorityAreaKeyword as pak where pak.key = :keyName";
Query query = entityManager.createQuery(jpql);
query.setParameter("keyName", key);
Hibernate stores enums as an oridnal. Or, when the field is annotated with #Enumerated(EnumType.STRING), as a string with the short name of the Enum. When annotated valid names would be {ALL, IOS, ANDROID}. Either way there is only a single field, the properties of the enum itself are not stored, they are constant after all.
If you want to query for an enum value you have to to query for pak.key = :key and use key as the parameter. Hibernate will do the required translation to ordinal or string.

SpringMVC 3 Convert <form:checkboxes ..> return String[] to Entity Object

I have an Entity Campaign that has a OneToOne relationship with CampaignCities cities.
In turn, CampaignCities contains a Set cities;
The campaign entity
#Entity
#javax.persistence.Table(uniqueConstraints={#UniqueConstraint(columnNames={"name","company_id"}), #UniqueConstraint(columnNames={"id"})})
public class Campaign implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
#NotEmpty
#Size(min=1, max=100)
private String name;
private Date startDate;
private Date endDate;
#Valid
private Deal deal;
#Valid
private Company company;
#OneToOne
private CampaignCities cities = new CampaignCities();
The CampaignCities entity
#Entity
public class CampaignCities {
private long id;
private Set<City> cities = new HashSet<City>();
#Id
#javax.persistence.GeneratedValue(strategy=GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#OneToMany
public Set<City> getCities() {
return cities;
}
public void setCities(Set<City> cities) {
this.cities = cities;
}
}
The City entity:
#Entity
public class City implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private Long id;
#javax.persistence.Id
#javax.persistence.GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
My NewCampaignController
#SessionAttributes(value={"campaign", "campaignCities"})
#Controller
public class NewCampaignController {
//private static final Logger logger = LoggerFactory.getLogger(NewDealController.class);
#Autowired
private CampaignManager campaignManager;
#Autowired
private CityManager cityManager;
#Autowired
SimpleDateFormat dateFormat;
#Autowired
CustomDateEditor dateEditor;
#RequestMapping(value = "campaign/new", method = RequestMethod.GET)
public String showForm(Map<String, Object> model) {
//List<Campaign> campaigns = campaignManager.getCampaigns();
Campaign campaignForm = new Campaign();
CampaignCities cities = new CampaignCities();
cities.setCities(new HashSet<City>(cityManager.getCity()));
//campaignForm.setCities(cities);
model.put("campaignCities", cities);
model.put("campaign", campaignForm);
return "campaign/new";
}
#RequestMapping(value = "campaign/new", method = RequestMethod.POST)
public String processForm(#Valid Campaign campaignForm, BindingResult result, Map<String,Object> model) {
new CampaignValidator().validate(campaignForm, result);
if (result.hasErrors()) {
return "campaign/new";
}
this.campaignManager.saveCampaign(campaignForm);
model.put("campaign", campaignForm);
model.put("campaigns", this.campaignManager.getCampaigns());
return "campaign/added";
}
I have been able to get campaign to render in a form and I've rendered the list of cities successfully using:
<form:checkboxes items="${campaignCities.cities}" path="cities" itemLabel="name" itemValue="id" delimiter="<br/>" />
However when i submit the form, I get the following validation error.
Field error in object 'campaign' on field 'cities': rejected value
[2,1]; codes
[typeMismatch.campaign.cities,typeMismatch.cities,typeMismatch.com.groupdealclone.app.domain.CampaignCities,typeMismatch];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable:
codes [campaign.cities,cities]; arguments []; default message
[cities]]; default message [Failed to convert property value of type
'java.lang.String[]' to required type
'com.groupdealclone.app.domain.CampaignCities' for property 'cities';
nested exception is java.lang.IllegalStateException: Cannot convert
value of type [java.lang.String[]] to required type
[com.groupdealclone.app.domain.CampaignCities] for property 'cities':
no matching editors or conversion strategy found]
I've tried to figure out a way to handle this in SpringMVC 3 but I've been stuck for over a day with no success. I simply want a List or Set or Cities that where checked on the form to be submitted to the controller and added to the Campaign. How do I get around the conversion problem where I can convert the String[] returned to a List or Set of Cities.
The project I'm working on is a public GitHub project, you can download the source and set it up using Maven if you like the project is called Group-Deal-Clone
After what is almost 2 days, the answer was simpler than I expected. Thanks to this thread I was guided to the answer.
In my NewCampaignController I did:
#InitBinder
public void initBinder(WebDataBinder binder) {
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, dateEditor);
binder.registerCustomEditor(CampaignCities.class, "cities", new PropertyEditorSupport() {
#Override
public void setAsText(String text) {
String [] ids = text.split(",");
CampaignCities cities = null;
for(String id:ids){
if(cities == null)
cities = new CampaignCities();
City city = cityManager.getCity(new Long(id));
if(city != null)
cities.getCities().add(city);
}
if(cities != null){
cities.setId(null);
setValue(cities);
}
}
});

Categories

Resources