Hibernate annotation for base java class - java

I would like to put into db a class that have java.awt.geom.Point2D field. Is it possible?
Here is my code.
#Entity
#Table(name = "my_class_table")
public class MyClass {
private String aliasId;
private Point2D field;
public Point2D getField() {
return field;
}
public void setFieldPoint2D field) {
this.field = field;
}
public String getAliasId() {
return aliasId;
}
public void setAliasId(String aliasId) {
this.aliasId = aliasId;
}
}
And the reason of the exception which is thrown:
Could not determine type for: java.awt.geom.Point2D, at table: my_class_table, for columns: [org.hibernate.mapping.Column(field)]
Of course, the reason is quite obvious. My question is: how should I annotate the class to be able to use a field of Point2D class? Is it possible at all?

The simplest way is to use a java.awt.Point that extends Point2D and is a Serializable class. This way hibernate will automatically map it with SerializableType and you don't need to do anything more. The point object will be saved in its serialized form in a blob database table column.
You have also the option to define a custom hibernate type for the Point2D class. Here is a link of how to define a custom hibernate type.

You can't add annotations to existing classes.
But you can define a CompositeUserType to tell Hibernate how to map a Point2D.

Thanks guys for response. Unfortunatelly java.awt.Point class uses Integer, so it is useless in my case. The easiest way to solve it would be to use Point2D.Double which implements Serializable (but definition of UserType or CompositeUserType is more convenient if you don't want to change class definition). So, the simple solution:
#Entity
#Table(name = "my_class_table")
public class MyClass {
private String aliasId;
private Point2D.Double field;
public Point2D.Double getField() {
return field;
}
public void setField(Point2D.Double field) {
this.field = field;
}
public String getAliasId() {
return aliasId;
}
public void setAliasId(String aliasId) {
this.aliasId = aliasId;
}
}
But my final goal was to create a class with ordered list of points. If anybody is interested here is an example of the class representing line:
#Entity
public class Line {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idDb", unique = true, nullable = false)
private int id;
#ElementCollection
#CollectionTable(name="points_table", joinColumns = #JoinColumn(name="idDb"))
#IndexColumn(name = "idx")
#Column(name="point_val")
private List<Point2D.Double> points = new ArrayList<Point2D.Double>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<Point2D.Double> getPoints() {
return points;
}
public void setPoints(List<Point2D.Double> points) {
this.points = points;
}
}

Related

hibernate - Persisting a composition interface of strategy pattern

I have the following class structure:
public abstract class Creature{
private String name;
//strategy pattern composition
private SkillInterface skill;
}
public interface SkillInterface {
void attack();
}
public class NoSkill implements SkillInterface {
#Override
public void attack() {
//statements
}
}
My goal is to persist Creature objects at one table in database. Subclasses of SkillInterface are without any fields. As they determine the behaviour, I want to convert selected SkillInterface class name to a String, as I only need to persist the classname of the current skill strategy of creature, with a String like skill.getClass().getSimpleName(). I tried to implement it with #Converter annotation, using AttributeConverter class to convert SkillInterface to String and save, but always had mapping exceptions. I want to be able to save it as String and retrieve as SkillInterface object.
But how can I implement it with Hibernate? Or do I have a design mistake?
Ok looks like I have found a basic solution that can be used to persist Strategy Pattern interfaces implementations. I used a #Converter annotation and a AttributeConverter class to convert strategy class names to column while saving to database and cast the retrieved String back to strategy class as following:
#Entity
public class Creature {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Convert(converter = SkillConverter.class)
private SkillInterface skill;
}
public class SkillConverter implements AttributeConverter<SkillInterface,String> {
#Override
public String convertToDatabaseColumn(SkillInterface skill) {
return skill.getClass().getSimpleName().toLowerCase();
}
#Override
public SkillInterface convertToEntityAttribute(String dbData) {
//works as a factory
if (dbData.equals("noskill")) {
return new NoSkill();
} else if (dbData.equals("axe")) {
return new Axe();
}
return null;
}
}
public interface SkillInterface {
public String getSkill();
void attack();
}
public class NoSkill implements SkillInterface{
public String getSkill() {
return getClass().getSimpleName();
}
#Override
public void attack() {
//strategy statements
}
}
You can use a proxy field to this for you like below:
abstract class Creature {
#Column
private String name;
// strategy pattern composition
private SkillInterface skill;
#Column
private String skillName;
public String getSkillName() {
return skill.getClass().getSimpleName();
}
public void setSkillName(String skillName) {
//ignore
}
}

save mongo entity to the different collections

I've been using Spring Data for saving entities to the mongo DB and my code at the moment looks like this:
I have a repo class:
public interface LogRepo extends MongoRepository<Log, String> {
}
and I have an Entity Log which looks like this:
#Document(
collection = "logs"
)
public class Log {
#Id
private String id;
private String jsonMessage;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getJsonMessage() {
return jsonMessage;
}
public void setJsonMessage(String jsonMessage) {
this.jsonMessage = jsonMessage;
}
}
and this work well for me, however this approach works only for the case if I want to save Log entities to "logs" collection. However it would be very nice for me to be able to save Log entity to different collections depending on the context. I mean it would be nice to define collection name in the runtime. Is it possible somehow?
Thanks, cheers
Try to use inheritance and define appropriate collection names in such way. May give you possibility to save in different collections but you will be still not able to specify dynamically collection names and resp. their amount at runtime.
#Document(
collection = "logs"
)
public class Log {
#Id
private String id;
private String jsonMessage;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getJsonMessage() {
return jsonMessage;
}
public void setJsonMessage(String jsonMessage) {
this.jsonMessage = jsonMessage;
}
}
#Document(
collection = "log_child"
)
public class LogChild extends Log{}
With the MongoOperations save method you can choose which class to use and
based on the class it will choose the appropriate collection.
#Document(collection = "collection_#{T(com.github.your_project.DBUtils).getCollectionName()}")
public Class Collection
You can change the name in real time using a static getter
#UtilityClass
public class DBUtils {
private String collectionName;
public String getCollectionName() {
return collectionName;
}
public void setCollectionName(String collectionName) {
DBUtils.collectionName = collectionName;
}
}

JavaFX and Data Binding with JPA entities

As the question says, I would like to know the easiest way to perform Data Binding to regular (non JavaFX) properties of JPA entities.
I was thinking there is probably some way to use the same binding functions if you make your entity class implement some interface for change listeners or something of the sort.
Here is an example of a JPA entity with property changed listeners.
#Entity
public class Ticket {
#Id
#GeneratedValue()
private int id;
#ManyToOne()
private EntryGate entryGate;
#ManyToOne()
private ExitGate exitGate;
#Transient
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
public Ticket() {
}
public Ticket(EntryGate owner) {
this();
this.entryGate = owner;
}
public void addListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void removeListener(PropertyChangeListener listener) {
changeSupport.removePropertyChangeListener(listener);
}
public int getId() {
return id;
}
public EntryGate getEntryGate() {
return entryGate;
}
public void setEntryGate(EntryGate entryGate) {
EntryGate oldGate = this.entryGate;
this.entryGate = entryGate;
changeSupport.firePropertyChange("entryGate", oldGate, this.entryGate);
}
public ExitGate getExitGate() {
return exitGate;
}
public void setExitGate(ExitGate exitGate) {
ExitGate oldGate = this.exitGate;
this.exitGate = exitGate;
changeSupport.firePropertyChange("exitGate", oldGate, this.exitGate);
}
}
Here is an example of a JavaFX property binding.
this.idLabel.textProperty().bind(this.ticket.idProperty().asString());
Obviously I can't replace my JPA properties with SimpleXXXProperty... because they are entities participating in object relational mapping.

Hibernate One to Many relationship with attributes on the relationship

Basic Hibernate question.
I have a class called Song and a class called Artwork, both exist independently. Then an instance of Song can contain multiple Artworks and when they do there are attribute particular to that relationship so I have created another class called CoverArt that links between the two. I'm using annotations for the hibernate stuff and having problems.
If I annotate all three classes as #Entity when I build the database I get the error >'org.hibernate.MappingException: Could not determine type for: Artwork, at table: CoverArt, for columns: [org.hibernate.mapping.Column(artwork)]'
If I change CoverArt to #Embeddable, as it only exists in the context of a Song I get the error
'org.hibernate.annotations.common.AssertionFailure: Declaring class is not found in the inheritance state hierarchy: com.jthink.songlayer.CoverArt'
I can't work out what these messages are saying, what I have wrong. Here is the relevant code from the three classes
Song:
#Entity
public class Song
{
#Id
#GeneratedValue
private Integer recNo;
#ElementCollection(fetch=FetchType.EAGER)
#IndexColumn(name = "POSITION")
private List<CoverArt> coverArt;
.....
CoverArt:
#Embeddable
public class CoverArt
{
private String imageType;
private String description;
private Artwork artwork;
#Id
#GeneratedValue
private Integer id;
public CoverArt()
{
}
public String getImageType()
{
return imageType;
}
public void setImageType(String imageType)
{
this.imageType = imageType;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public Artwork getArtwork()
{
return artwork;
}
public void setArtwork(Artwork artwork)
{
this.artwork = artwork;
}
}
Artwork:
#Entity
public class Artwork
{
public Artwork()
{
}
public Artwork(byte[] imageData)
{
this.imageData=imageData;
}
#Id
#GeneratedValue
private Integer id;
#Lob
private byte[] imageData;
private String mimeType;
private int width;
private int height;
public byte[] getImageData()
{
return imageData;
}
public void setImageData(byte[] imageData)
{
this.imageData = imageData;
}
public String getMimeType()
{
return mimeType;
}
public void setMimeType(String mimeType)
{
this.mimeType = mimeType;
}
public int getWidth()
{
return width;
}
public void setWidth(int width)
{
this.width = width;
}
public int getHeight()
{
return height;
}
public void setHeight(int height)
{
this.height = height;
}
}
The CoverArt class should be an entity.
The Song has a list of CoverArt instances, you should thus have
#OneToMany
#JoinColumn(...)
private List<CoverArt> coverArts; // note the final s, since it's plural
Each CoverArt links to an Artwork, so you should also have an association. It's not clear if it's a ManyToOne or a OneToOne, tough. I'll suppose it's a OneToOne:
#OneToOne
#JoinColumn(...)
private Artwork artwork;
It's pretty simple. Each time an entity has a reference to another entity, or a collection of another entity instances, you have an assosiation. And an association can be a OneToMany, OneToOne, ManyToOne or ManyToMany. You have to tell Hibernate which one it is. If you don't tell it, it assumes it's a simple Column which is wrong.
First of all You should tell us how do You want all that to look like in database.
I assume You want something like that:
table 'songs'
table 'artworks'
table 'cover_arts' with fkeys: song_id and artwork_id
So a Song "has many" CoverArts and each CoverArt "has one" Artwork.
If this is correct, then:
Annotate CoverArt with #Entity instead of #Embeddable
inside CoverArt class annotate field 'artwork' with #ManyToOne
replace #ElementCollection on field 'coverArt' inside Song class with #OneToMany. It would be nice to rename field 'coverArt' to 'coverArts' as it is a collection, not a single instance.

Persisting a Collection class with ORMLite in android

I have two classes setup like the following. I am confused as to when I need to annotate something as an foreign collection and when I do not. This may also sound silly, but nowhere in the ORMLite documentation does it say whether or not a non-foreign collection is allowed. What if I have a List of ints which get autoboxed into Integers? can I just persist this using a standard #DatabaseField above the Collection? A foreign collection, according to ORMLite, must also have back reference for it to work (a reference to the parent, given a one to many realtionship). For the example below, I am assuming you should annotate myBList as a foreign collection as well as making myA a foreign object, but how could you handle myStringList?
I Have seen sample code here but it doesn't answer my questions: http://ormlite.com/docs/examples
public class A {
private Set<B> myBList = new HashSet<B>();
private List<String> myStringList = new ArrayList<String>();
private long id;
public A(){}
public Set<B> getMyBList() {
return myBList;
}
public void setMyBList(Set<B> myBList) {
this.myBList = myBList;
}
public List<String> getMyStringList() {
return myStringList;
}
public void setMyStringList(List<String> myStringList) {
this.myStringList = myStringList;
}
public void setId(long id){
this.id = id;
}
public long getId(){
return id;
}
}
public class B {
private int myInt;
private String myString;
private A myA;
private long id;
public B(){}
public A getMyA(){
return myA;
}
public A setMyA(A a){
myA = a;
}
public int getMyInt() {
return myInt;
}
public void setMyInt(int myInt) {
this.myInt = myInt;
}
public String getMyString() {
return myString;
}
public void setMyString(String myString) {
this.myString = myString;
}
public void setId(long id){
this.id = id;
}
public long getId(){
return id;
}
}
#Robert is correct. When hibernate persists a collection (or even an array), it does so with hidden extra tables with foreign ids -- in other words hidden foreign collections. ORMLite tries to adhere to the KISS principle and so has you define the foreign collections "by hand" instead.
I've added more details about storing collections.
http://ormlite.com/docs/foreign-collection
This means that you cannot persist an Integer type because there is no foreign-id. Also, your code can define a foreign collection Collection<Order> or ForeignCollection<Order>. Either one will be set with a ForeignCollection. ORMLite does not support lists or other collection types.
If you want to save a Collection (such as an ArrayList) of objects to ORMLite the easiest way is this:
#DatabaseField(dataType = DataType.SERIALIZABLE)
private SerializedList<MyObject> myObjects;
and to get my list of objects:
public List<MyObject> getMyObjects() {
return myObjects;
}

Categories