I'm trying to store in the GAE DB a class which some of its fields are classes themselves.
Just before going into more details I want to say it worked just fine before I added these new class field.
So, I followed the documentation here: https://developers.google.com/appengine/docs/java/datastore/jdo/dataclasses
and I'm getting this error :
org.datanucleus.jdo.exceptions.ClassNotPersistenceCapableException: The class "The class "sporteam.web.client.User" is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found." is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data for the class is not found.
The main class I'm trying to use is User:
#SuppressWarnings("serial")
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User implements Serializable
{
// data members
// user unique facebook id
#Persistent
#PrimaryKey
private String facebook_id;
// users facebook code
#Persistent
private String facebook_code;
// users device ID code
#Persistent
private String dev_id;
// users registration ID code
#Persistent
private String reg_id;
// user first name
#Persistent
private String first_name;
// user last name
#Persistent
private String last_name;
// user age, should be grater then 8
#Persistent
private int age;
// user email, as setup in facebook
#Persistent
private String email;
// user weight, should be greater then 40
#Persistent
private double weight;
// user workout_level (0.8 is the highest(best shape) and 1 is the lowest)
#Persistent
private double workout_level;
// user gender ("male"/"female"/"unknown")
#Persistent
private String gender;
#Persistent
#Embedded
private UserTracks userTracks = null;
// default constructor
public User()
{
}
//....
}
This is the UserTracks class:
#PersistenceCapable
#EmbeddedOnly
#SuppressWarnings("serial")
public class UserTracks implements Serializable
{
#Persistent
#Embedded
//#Element(embedded="true")
private List<Track> tracks = null;
#Persistent
private long date = 0;
public UserTracks()
{
}
}
And theses are the other 2 classes used:
#PersistenceCapable
#EmbeddedOnly
#SuppressWarnings("serial")
public class Track implements Serializable
{
/** running information **/
#Persistent
private double avgSpeed = 0;
#Persistent
private double distance = 0;
#Persistent
private double calories = 0;
#Persistent
private long time = 0;
/************************/
#Persistent
private long date = 0;
#Persistent
private String name = null;
#Persistent
#Embedded
private List<GeoPtr> track = null;
public Track()
{ // needed for Serializable
}
}
GeoPtr:
#PersistenceCapable
#EmbeddedOnly
#SuppressWarnings("serial")
public class GeoPtr implements Serializable
{
/** the speed is in m/s **/
#Persistent
float speed;
#Persistent
long time;
#Persistent
double altitude;
#Persistent
double latitude;
#Persistent
double longitude;
#Persistent
double calorie = 0;
public GeoPtr()
{ //needed for Serializable
}
}
As far as I can see, every class is PersistenceCapable and all the fields are either PersistenceCapable themselves or a collection of it and according to the documentation above it should work.
Ideas?
Thanks
You try to use embedded class Track to store collection of GeoPtr to UserTracks. How DataStore will handle it? When embedding into UserTracks fields of GeoPtr added to common single record in DataStore. You will have:
avgSpeed, distance, ...., speed, time
What DataStore should do in collection case?
avgSpeed, distance, ...., speed_1, time_1, ..., speed_2, time_2, ... speed_N, time_N
???
Is this make any sence?
Don't use embedded. Create three separate classes with primary keys. Use one-to-one relationship for User - UserTracks and one-to-many for UserTracks - GeoPtr.
Read about relations here
Well apparently there is some problem with embedding a collection of user defined classes.
I've read somewhere that its not possible to embed a collection field that has an embedded collection field itself. However, you can achieve almost the same by serializing these fields (you wont be able to index them - that's the difference between serialized to embedded, but I don't need indexes on these fields for my use so it worked out just fine) you can do so by using the next notation :
#Persistent(serialized = "true")
Hoped it will save all of you the pain I've been through.
Bar.
Related
We are building an application that needs to store differences made on existing opbjects.
Afterwards we will store these changes to the database. However for some reason the #diffIgnore option is not working on our User.class.
Every object extends our baseEntityCMS class, which has a property User. This is meant to store our update user information after the compare by JaVers is done. For some reason the user object is still compared even after setting #diffIgnore on property level and on class level.
Here is the code:
BaseEntityCMS.java
public class BaseEntityCMS extends BaseEntity {
private Boolean active;
private LocalDateTime inactiveDateTime;
private LocalDate creationDate;// in original application
private LocalDate importDate;
private LocalDate startDate;
private LocalDate endDate;
#Embedded
#DiffIgnore
private User modifierUser;
...
}
CodeList.java
public class CodeList extends BaseEntityCMS {
private String companyCode;
private Application sourceApplication;
private String name;
private String format;
private int length;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "codeList")
private List<Description> descriptionList;
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "codeListList")
private List<Keyword> keywords;
private String domainOwner;
#OneToMany(cascade = CascadeType.REFRESH)
private List<Attribute> attributeList;
...
}
User.java
#Embeddable
#AllArgsConstructor
#Builder
#DiffIgnore
public class User {
private String userName;
}
TestCodeList.java
#Test
public void compareCodeListTest() {
Javers javers = JaversBuilder.javers().withListCompareAlgorithm(ListCompareAlgorithm.LEVENSHTEIN_DISTANCE)
.registerValueObject(BaseEntity.class).registerValue(Code.class).registerValue(Attribute.class)
.registerValue(AttributeValue.class).registerValue(MapCodeAttribute.class)
.registerValueObject(User.class).build();
CodeList codeListNew = createCodeListTest("ServiceTest");
CodeList codeListNew2 = createCodeListTest("ServiceTest");
Diff diff = javers.compare(codeListNew2, codeListNew);
assertNull(diff.getChanges());
}
So in the test class we create 2 CodeLists (codeListNew and codeListNew2) with a standard method.
Inside this method everything is created the same except we create a new User every time.
Because all properties of codeList (attribute, attributeValue, ...) extend the BaseEntityCMS class they all have a User property.
This is the output we get:
changes on xxx.CodeList/ :
- 'attributeList' collection changes :
1. 'Attribute(name=Address, format=freeformat, length=10, numberOfDecimals=2, description=description attribute, optional=true)' changed to 'Attribute(name=Address, format=freeformat, length=10, numberOfDecimals=2, description=description attribute, optional=true)'
0. 'Attribute(name=Number of employees, format=freeformat, length=10, numberOfDecimals=2, description=description attribute, optional=true)' changed to 'Attribute(name=Number of employees, format=freeformat, length=10, numberOfDecimals=2, description=description attribute, optional=true)'
- 'mapCodeAttributeMap' map changes :
'Code(super=BaseEntityCMS(super=BaseEntity(id=null), active=true, inactiveDateTime=null, creationDate=2020-03-23, importDate=2020-03-23, startDate=2020-03-23, endDate=2025-12-31, modifierUser=codems.agza.datalayer.model.User#57f83dc7), code=code1)' -> 'MapCodeAttribute(super=BaseEntity(id=null))' added
'Code(super=BaseEntityCMS(super=BaseEntity(id=null), active=true, inactiveDateTime=null, creationDate=2020-03-23, importDate=2020-03-23, startDate=2020-03-23, endDate=2025-12-31, modifierUser=codems.agza.datalayer.model.User#75937998), code=code1)' -> 'MapCodeAttribute(super=BaseEntity(id=null))' removed
We actually expect no difference since everything is the same but the User. This user is marked with #DiffIngore? How come we still have differences?
Forgot: we use
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
<version>5.8.11</version>
</dependency>
I have two tables clients and contact :
public class Contacts implements Serializable{
#Id
#GeneratedValue
private Long idContacts;
private String nomContacts;
private String prenomContacts;
private String telephone;
private String autreTelephone;
private String fax;
private String email;
private int deleted = 0;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "idClient")
private Client client;
}
and I declared an instance of Contact:
Contacts contact = new Contacts()
How can I set the foreign key of Contact manually I tried : contact.getClient().setIdClient(1) and it did not work.
A major purpose of JPA is to avoid manually fiddling with relationship keys; instead, just use regular Java references. For what you're trying to do:
Client clientOne = clients.find(1L); // or get the client some other way
contact.setClient(clientOne);
Note that Spring Data (in addition to autoimplemented repositories) provides a converter, so that if you have a method argument for your controller that refers to an existing object's ID, you can pass the object itself instead of looking up manually:
#GetMapping("/clients/{id}")
public Client getClient(#PathVariable("id") Client client) {
return client;
}
Really appreciate ANY help (at least ways how to trace root cause of the problem) because I've been fighting with this for several days and didn't find even workaround.
The problem itself: I have a few entities, all of them work good - persist(), find() etc. except one method where I create two different entities (Order and Items, one order can have many Items). After calling em.persist(..) order is saved and I see its id generated by DB, item is saved to DB (I see it through SELECT directly in DB) but it shows ID=0. And whatever I do it always 0 (e.g. when I open the order I still see its ID=0) until I restart server - then it shows correct ID of item.
Code of the method (after logging I added actual values I get):
public void createOrderFromItems(ArrayList<TehnomirItemDTO> items, User user) {
Order ord = new Order();
User managers = getUserByEmail(Constants.ALL_MANAGERS_GROUP);
ord.setAssignedTo(managers);
Date date = new Date();
ord.setCreatedOn(date);
User customer = user;
ord.setCustomer(customer);
BigDecimal custBalance = new BigDecimal(0);
ArrayList<Balance> balances = getBalanceForUser(customer);
for (Balance b:balances) {
custBalance.add(b.getAmount());
}
logger.debug("before1. order: "+ord.getOrderId()); //here I get 0
em.persist(ord);
logger.debug("before2. order: "+ord.getOrderId()); //still 0
State new_state = getStateByName(SharedConstants.STATE_NEW);
logger.debug("before3. order: "+ord.getOrderId()); //here I get actual ID, generated by DB, e.g. 189
State overpriced = getStateByName(SharedConstants.STATE_LIMIT_EXCEEDED);
ArrayList<Item> itemList = new ArrayList<Item>();
for (TehnomirItemDTO tid:items) {
Item item = new Item(tid);
item.setOrder(ord);
logger.debug("order inside2:"+ord.getOrderId()); //again, actual ID
item.setPriceInt(tid.getPrice_int());
custBalance = custBalance.subtract(item.getPriceInt());
if (custBalance.floatValue()>0) {
item.setStateBean(new_state);
} else item.setStateBean(overpriced);
logger.debug("item before:"+item.getItemId()); //here I get 0
em.persist(item);
item = em.merge(item);
em.setFlushMode(FlushModeType.COMMIT);//added just in case it would work but it didn't
em.flush();//same as previous line
Item tst = getItemByID(1);
logger.debug("item after:"+item.getItemId()+" ord:"+ord.getOrderId()); //again, orderID is correct, itemID is 0
itemList.add(item);
}
ord.setItems(itemList);
State new_state2 = getStateByName(SharedConstants.STATE_NEW);
logger.debug(ord.getItems().get(0).getItemId()+" order: "+ord.getOrderId());//again, orderID is correct, itemID is 0
}
Order class:
#Entity
#Table(name="orders")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY/*, generator="ORDERS_ORDERID_GENERATOR"*/)
#Column(name="ORDER_ID")
private int orderId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="CREATED_ON")
private Date createdOn;
//bi-directional many-to-one association to Item
#OneToMany(mappedBy="order")
private List<Item> items;
//uni-directional many-to-one association to User
#ManyToOne
#JoinColumn(name="ASSIGNED_TO")
private User assignedTo;
//uni-directional many-to-one association to User
#ManyToOne
#JoinColumn(name="CUSTOMER")
private User customer;
public Order() {
}
public int getOrderId() {
return this.orderId;
}
}
Item class (removed getters and setters to make it more readable):
#Entity
#Table(name="items")
public class Item implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="ITEM_ID")
private int itemId;
private String code;
private BigDecimal weight;
public BigDecimal getWeight() {
return weight;
}
public void setWeight(BigDecimal weight) {
this.weight = weight;
}
private String comments;//any additional info user'd like to add
private String description;
#Column(name="EXT_ID")
private int extId;
private String manufacturer;
#Column(name="PRICE_EXT")
private BigDecimal priceExt;
#Column(name="PRICE_INT")
private BigDecimal priceInt;
private String region;
private String term;
//bi-directional many-to-one association to Order
#ManyToOne(cascade=CascadeType.PERSIST)
#JoinColumn(name="ORDER_ID")
private Order order;
//bi-directional many-to-one association to State
#ManyToOne
#JoinColumn(name="STATE")
private State state;
}
I had some thoughts about caching so I added to my persistence.xml lines
property name="toplink.cache.type.default" value="NONE"
property name="toplink.cache.type.Order" value="NONE"
but it didn't help either
Try to change int to Integer
private Integer orderId;
and getters and setters as well.
You mention Item is assigned an ID value by the database, but missed the #GeneratedValue(strategy=GenerationType.IDENTITY) annotation you have on order. This is what tells JPA the db controls the value, otherwise it expects the application to set it, keeping it the default 0.
after calling em.persist(obj), call em.flush();. It should work.
better have a private method save
like
private void save(object obj)
{
em.persist(obj);
em.flush();
}
I have a composite object that I wish to store in mongodb (using spring annotations). The object is as follows:
#Document(collection="person")
class Person {
#Id
private String id;
private Address address;
private String name;
}
and the composite class Address:
#Document
class Address {
#Indexed
private Long countryId;
private String street;
#Indexed
private String city
}
I need both country and city to be indexed as part of the person collection. Alas, no index is created for them. Any ideas how to create the index?
I have tried the following which works but is not elegant:
#Document(collection="person")
#CompoundIndexes({
#CompoundIndex(name = "countryId", def = "{'address.countryId': 1}")
})
class Person {
You can set up multiple secondary indexes, if you wish. This would be a good place to start.
I have just one week experience in GAE/Java and trying to port an legacy application(developed using PHP/MySQL) to GAE+JDO. I'm now stuck with a basic issue in creating a relationship between two tables(kinds in GAE).
So here is the case:
We have a Users table which holds the user authentication information. It also has a field user_role which store role_id, which is actually a foreign key of another table user_roles.
From the the Entity-Relationship documentation in GAE, I understand that DataStore doesn't support foreign-key relationships and designed the Users class by adapting the Employee-ContactInfo example in the docs.
When I executed the application, the user_roles kind is inserted each time I add an entry in Users table. The user_roles kind is supposed to have only three static values. But this is having redundant values as I input more records in Users.
I think that I'm missing something very trivial, but I couldn't figure it out due to my inexperience to datastore. It would be very nice if someone could guide me to solve this issue.
Here is the code:
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Users {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private String userName;
#Persistent
private String password;
#Persistent
private String salt;
#Persistent
private Date createdDate;
#Persistent
private Key createdBy;
#Persistent
private Date lastLogin;
#Persistent
private boolean status;
#Persistent
private String authKey;
#Persistent(defaultFetchGroup="true")
private SecurityRole securityRole;
#Autowired
SecurityRepository securityRepository ;
public SecurityPrincipals(String userName, String password,SecurityRole securityRole,boolean status) {
this.securityRole = securityRole;
this.userName = userName;
this.password = password;
this.status = status;
}
//getters and setters
}
Definition for Roles:
#PersistenceCapable(detachable="true")
public class SecurityRole {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private String securityRoleName;
#Persistent
private String securityRoleDescription;
#Persistent
private String securityRoleStatus;
#Persistent
private Date securityRoleCreatedDate;
public SecurityRole(String securityRoleName, String securityRoleDescription, String securityRoleStatus,String securityBaseType)
{
this.securityRoleName = securityRoleName;
this.securityRoleDescription = securityRoleDescription;
this.securityRoleStatus = securityRoleStatus;
this.securityBaseType = securityBaseType;
}
// getters and setters
}
The relevant code from Controller:
SecurityRole securityRole = securityRepository.getSecurityRole( securityRoleName);
users = new Users(userName,password,status,securityRole);
iUserRepository.save(employeeDetails);
Here is the definition of getSecurityRole:
public SecurityRole getSecurityRole(String securityRoleName)
{
PersistenceManagerFactory pmf = this.jdoTemplate.getPersistenceManagerFactory();
PersistenceManager pm = pmf.getPersistenceManager();
try {
Query query = pm.newQuery( SecurityRole.class);
query.declareImports("import java.lang.String");
query.declareParameters("String securityRoleName");
query.setFilter("this.securityRoleName == securityRoleName");
List<SecurityRole> securityRoles = (List<SecurityRole>)query.execute(new String(securityRoleName));
SecurityRole temp = null;
for(SecurityRole securityRole: securityRoles)
{
temp = securityRole;
}
return temp;
}
finally {
pm.close();
}
}
Here is the definition of iUserRepository.save():
public void save(Users user) {
jdoTemplate.makePersistent(companyDetails);
}
In the Users class, you have the defined the property
#Persistent(defaultFetchGroup="true")
private SecurityRole securityRole;
This statement creates an "owned" relationship in GAE datastore, which means that when you create an object of the Users class, an object of the SecurityRole class will be created as well.
What you need, is an unowned relationship that can be created as follows:
#Persistent(defaultFetchGroup="true")
private Key securityRole;
In this way, a SecurityRole object is not created each time you create an instance of the Users class. For more information about owned and unowned relationships, take a look at http://code.google.com/appengine/docs/java/datastore/jdo/relationships.html
Hope this helps!