Ok, lets say I have a model.
#Entity
public class Person extends Model {
public String name;
public String email;
}
Now. I have a couple of transient fields that don't exist in the database, but I need to access them. Basically they are fields for displaying the Person on a web page.
#Entity
public class PersonDisplay extends Person {
#Transient
public String DT_RowClass = "";
#Transient
public String cellColor = "";
}
Is it possible to query the PersonDisplay and get the Person object plus the PersonDisplay default values?
Like this.
PersonDisplay display = PersonDisplay.find("byEmail" , "test#test.com").first();
I'm running into a few errors when I do this.
Let me know if I need to explain this again.
Look up the #PostLoad annotation, which you can use to initialize any transient variables.
Related
I have two functions to encrypt and decrypt data.
My current code is as below. I have entity class, DTO class, repository and service class.
The name need to be encrypted before save to database and to be decrypted when retrieve from database.
Lets say I have 10 different entity classes need to do the encryption and decryption data, I need to add the encryption and decryption function to each service class as below codes.
Is there any way to do all the encryption and decryption data in one service class for all the entity? like overriding the Get and Set method in entity? Anyone can advice? Thanks a lot.
#Entity
#Getter
#Setter
public class Customer {
private Long id;
private String name;
private String contact;
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class CustomerDTO {
private String name;
}
#Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>{
}
#Service
public class CustomerService {
#Autowired
private CustomerRepository customerRepository;
#Autowired
private EncrytionService encrytionService;
public void save(String name){
Customer customer = new Customer();
customer.setName(encrytionService.doEncrypt(name));
customerRepository.save(customer);
}
public CustomerDTO getCustomer(Long customerId) {
Customer customer = customerRepository.findById(customerId);
CustomerDTO dto = new CustomerDTO();
dto.setName(encrytionService.doDecrypt(customer.getName()));
return dto;
}
}
Not sure there is a way to do that easily (kinda out-of-the-box way), but maybe you could try to implement something yourself using JPA lifecycle events and EntityListener.
For example:
// this is going to be our EntityListener
public class SensitiveDataListener {
#PrePersist
void beforeAnyPersist(Customer customer) {
// encrypt what you need and set
// e.g. customer.setName(encrytionService.doEncrypt(customer.getName()));
}
// after an entity has been loaded
#PostLoad
void afterLoad(Customer customer) {
// decrypt what you need
}
}
// and this is how you add it to your entity
#EntityListeners(SensitiveDataListener.class)
#Entity
public class Customer {
//...
}
A good question here would be - ok I have multiple entities, what do I do - create multiple **Listener classes? In general, no. Your listener can "handle" multiple entities, but how to make it happen - depends on what you need - for instance, if you need to encrypt/decrypt different fields in different entity that's one case, and if you need encrypt/decrypt let's say name and you have this field in different entities, that would be another case and another solution. Also, you might want to encrypt everything and again that would be a different solution because it is yet another use case.
If it is the same field you could probably "unify" you entities (but keep in mind sometimes it is not a good idea when your entities implement some interfaces):
public interface Sensitive {
void setName(final Date date);
}
#EntityListeners(SensitiveDataListener.class)
#Entity
public class Entity1 implements Sensitive {
// override setName
}
#EntityListeners(SensitiveDataListener.class)
#Entity
public class Entity2 implements Sensitive {
// override setName
}
// but then your SensitiveDataListener will look like this
public class SensitiveDataListener {
#PrePersist
void beforeAnyPersist(Sensitive entity) {
// encrypt what you need and set
// e.g. entity.setName(encrytionService.doEncrypt(entity.getName()));
}
// after an entity has been loaded
#PostLoad
void afterLoad(Sensitive entity) {
// decrypt what you need
}
}
Maybe you could also use AttributeConverter, assuming your field is String and encoded value is also String you could create converter which will encode/decode your stuff, but then you need to add it to every field (in every entity) you want to encode.
Something like this:
#Convert(converter = MyAttributeConverter.class)
private String name; // this is entity field
I am pretty new in Spring Data JPA and ORM in general. I have the following architectural doubt.
Lets consider this entity class:
#Entity // This tells Hibernate to make a table out of this class
public class Order {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name = "name")
private String fullName;
private String address;
private String product;
#Column(name = "order_date_time")
private String orderDate;
private Double quantity;
// getters, setters
}
This class is mapped on my order database table.
In my application data came from an Excel document that I parse via Apace POI and than I have to persist on the database.
My doubt is: can I directly use this entity class to map an Excel row using Apache POI in order to persist the Excel rows as order table records? Or is better to use another DTO class to read the rows from Excel and than use this DTO to set the field values of my entity class?
An entity class can contain a constructor using fields?
Can I directly use this entity class to map an Excel row using Apache
POI in order to persist the Excel rows as order table records?
Yes you can.
Or is better to use another DTO class to read the rows from Excel and
than use this DTO to set the field values of my entity class?
It's certainly common to have a DTO layer between the two, but it's not required so it's up to you.
An entity class can contain a constructor using fields?
Yes, but at least Hibernate wants a non-private default constructor as well, so remember to create a protected Order() {} (or any visibility modifier besides private) in addition to your parameterized constructor.
I'm not a heavy user of Apache POI, but I do know it's used to manipulate MS files.
So, here are my two cents, in your use case, you can just read it and map directly to the Entity class as it doesn't expose an API to the external world.
However, if you were building a REST/SOAP API, I recommend you put a DTO in between so you don't mistakenly expose things that shouldn't be exposed.
From architectural point of view better to have a DTO class and encapsulate some logic there.
class CsvOrder {
private String fullName;
private String address;
public CsvRecord(String[] record) {
fullName = get(record, FULLNAME_INDEX);
address = get(record, ADDRESS_INDEX);
}
public Order toOrder() {
Order result = new Order();
result.setFullName(fullName);
return result;
}
}
public static <T> T get(T[] arr, int index) {
final T notFound = null;
return index < size(arr) ? arr[index] : notFound;
}
public static <T> int size(T[] array) {
return array == null ? 0 : array.length;
}
You can put a static method toOrder() to OrderServiceMapper, if you want to totally decouple layers
class OrderServiceMapper {
public static Order toOrder(CsvOrder order) {
Order result = new Order();
result.setFullName(order.getFullName());
return result;
}
}
Also, use Integer in place of int for id. Better to use Long everywhere
// This tells Spring to add this class to Hibernate configuration during auto scan
#Entity
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
}
I have a Java Entity that has several well defined functors. I want to persist them so as not factorize the object once it is fetched from the database. Is there a way to do so with Ebean?
I think that I could get it saving the class name that implements those functors as a String in the entity and in the setter of that string implement the setter of the functor with Reflection. Any other idea?
Class Example:
#Entity
public Foo extends Model
{
#Id
private Long id;
#Transient
private Runnable functor;
private String classFunctor;
public void setClassFunctor(String value)
{
//Here I implement the Reflection routine to load the functor.
}
}
I'm trying to use inheritance with ORMLite and I can't work out if it is supported or not from looking at the documentation and googling.
What I want to do is have
public abstract class Person{
public int id;
public String name;
}
public class Student extends Person{
public String school;
public String year;
// other student stuff
}
public class Teacher extends Person{
public String title;
// other teacher stuff
}
What I can't work out (assuming it's supported) is how to annotate the 3 classes for ORMLite.
Do I only need to annotate the concrete classes with #DatabaseTable(tableName = "Student") or do I need the abstract class also?
I keep getting errors like:
04-24 10:18:30.857: E/AndroidRuntime(30495): Caused by: java.lang.RuntimeException: java.sql.SQLException: Unknown field 'name' from the Android sqlite cursor, not in:[year, school]
The #DatabaseTable annotation is only necessary on the Student or Teacher tables and would not be used if it was on the Person base class.
What you need to have is a #DatabaseField annotation on the id and name fields in Person. For example:
public abstract class Person{
#DatabaseField(generatedId = true)
public int id;
#DatabaseField
public String name;
}
ORMLite should walk the class hierarchy and any fields from the base class should be included in the Student and Teacher tables. If you edit your question to show the #DatabaseField or other annotations, I can comment more.
Ok for that but now, how to implements, in that example, a fourth class containing a List<AbstractPerson> ?
I precise my question :
public class ClassRoom {
#ForeignCollectionField(foreignFieldName="asYouWant")
public Collection<Person> peoples;
}
peoples.add(new Student());
peoples.add(new Teacher());
peoples.add(new Student());
because when ormlite will try to access peoples like :
for (Person person : classRoom.peoples)
{
if (person.getType() == Student)
//do stuff
else if (person.getType() == Student)
//do other stuff
}
It won't be able to get personDAO because it doesn't exist (abstract)...
I get all my database functionnal with good Id's and relation, it's just a data access question ?
I have a problem trying to map an inheritance tree. A simplified version of my model is like this:
#MappedSuperclass
#Embeddable
public class BaseEmbedded implements Serializable {
#Column(name="BE_FIELD")
private String beField;
// Getters and setters follow
}
#MappedSuperclass
#Embeddable
public class DerivedEmbedded extends BaseEmbedded {
#Column(name="DE_FIELD")
private String deField;
// Getters and setters follow
}
#MappedSuperclass
public abstract class BaseClass implements Serializable {
#Embedded
protected BaseEmbedded embedded;
public BaseClass() {
this.embedded = new BaseEmbedded();
}
// Getters and setters follow
}
#Entity
#Table(name="MYTABLE")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
public class DerivedClass extends BaseClass {
#Id
#Column(name="ID", nullable=false)
private Long id;
#Column(name="TYPE", nullable=false, insertable=false, updatable=false)
private String type;
public DerivedClass() {
this.embedded = new DerivedClass();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Embeddable
public static NestedClassA extends DerivedEmbedded {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
}
public DerivedClassA() {
this.embedded = new NestedClassA();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Embeddable
public static NestedClassB extends DerivedEmbedded {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
}
public DerivedClassB() {
this.embedded = new NestedClassB();
}
// Getters and setters follow
}
At Java level, this model is working fine, and I believe is the appropriate one. My problem comes up when it's time to persist an object.
At runtime, I can create an object which could be an instance of DerivedClass, DerivedClassA or DerivedClassB. As you can see, each one of the derived classes introduces a new field which only makes sense for that specific derived class. All the classes share the same physical table in the database. If I persist an object of type DerivedClass, I expect fields BE_FIELD, DE_FIELD, ID and TYPE to be persisted with their values and the remaining fields to be null. If I persist an object of type DerivedClass A, I expect those same fields plus the FIELD_CLASS_A field to be persisted with their values and field FIELD_CLASS_B to be null. Something equivalent for an object of type DerivedClassB.
Since the #Embedded annotation is at the BaseClass only, Hibernate is only persisting the fields up to that level in the tree. I don't know how to tell Hibernate that I want to persist up to the appropriate level in the tree, depending on the actual type of the embedded property.
I cannot have another #Embedded property in the subclasses since this would duplicate data that is already present in the superclass and would also break the Java model.
I cannot declare the embedded property to be of a more specific type either, since it's only at runtime when the actual object is created and I don't have a single branch in the hierarchy.
Is it possible to solve my problem? Or should I resignate myself to accept that there is no way to persist the Java model as it is?
Any help will be greatly appreciated.
Wow. This is the simplified version? I assume that the behavior that you are seeing is that BaseEmbedded field is persisted but not the FIELD_CLASS_A or B?
The problem is that when Hibernate maps the DerivedClassA and B classes, it reflects and sees the embedded field as a BaseEmbedded class. Just because you then persist an object with the embedded field being a NestedClass, the mapping has already been done and the FIELD_CLASS_A and B are never referenced.
What you need to do is to get rid of the NestedClass* and embedded field and instead have the fieldClassA and B be normal members of DerivedClassA and B. Then add add a name field to the #Entity which will put them both in the same table I believe. This will allow you to collapse/simplify your class hierarchy a lot further.
See: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1168
#Entity(name = "DerivedClass")
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
...
#Entity(name = "DerivedClass")
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
...