Google App Engine - JDODetachedFieldAccessException - google-app-engine

I'm pretty new to JPA/JDO and the whole objectdb world.
I have an entity with a set of strings, looks a bit like:
#Entity
public class Foo{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Key id;
private Set<String> bars;
public void setBars(Set<String> newBars){
if(this.bars == null)
this.bars = new HashSet<String>;
this.bars = newBars;
}
public Set<String> getBars(){
return this.bars;
}
public void addBar(String bar){
if(this.bars == null)
this.bars = new HashSet<String>;
this.bars.add(bar);
}
}
Now, in another part of the code, I'm trying to do something like this:
EntityManager em = EMF.get().createEntityManager();
Foo myFoo = em.find(Foo.class, fooKey);
em.getTransaction().begin();
myFoo.addBar(newBar);
em.merge(myFoo);
em.getTransaction().commit();
When, of course, newBar is a String.
But, what I get is:
javax.jdo.JDODetachedFieldAccessException: You have just attempted to access field "bars" yet this field was not detached when you detached the object. Either dont access this field, or detach it when detaching the object.
I've searched for an answer, but I couldn't find one.
I've seen someone ask about a Set of strings, and he was told to add an #ElementCollection notation.
I tried that, but I got an error about the String class Metadata (I don't really understand what it means.)
I would really appreciate some help on this thing, even a good reference to someone explaining this (in simple English).

OK,
So I found the answer in some blog.
So for anyone who's interested:
In order to use a Collection of simple data types (in JPA), a
#Basic
notation should be added to the collection. So from my example at the top, It should've been written:
#Basic
private Set<String> bars;

So you are using JPA, right? (I see EntityManager rather than JDO's PersistenceManager.) Since you are getting a JDO error, I suspect that your app isn't configured properly for JPA.
JPA docs: http://code.google.com/appengine/docs/java/datastore/jpa/overview.html
JDO docs: http://code.google.com/appengine/docs/java/datastore/jdo/overview.html
You need to pick one datastore wrapper and stick with it. The default new app with the Eclipse tools is configured for JDO, and it is a reasonable choice, but you'll have to change your annotations around a little bit.

Related

How to unindex lists in Objectify?

Why is it not possible to unindex a list of an objectify entity?
To demonstrate the problem I made a simple example project.
I used the entity
#Entity
public class Car {
#Id String id;
#Unindex List<Passenger> passengers;
}
an the object
public class Passenger {
String name;
}
and saved it using this simple method.
public class CarFactory {
public void writeCarEntity() {
Car car = new Car();
car.setId("myCar");
List<Passenger> passengers = new LinkedList<Passenger>();
Passenger carl = new Passenger();
carl.setName("Carl");
Passenger pete = new Passenger();
pete.setName("Pete");
Passenger jeff = new Passenger();
jeff.setName("Jeff");
passengers.add(carl);
passengers.add(pete);
passengers.add(jeff);
car.setPassengers(passengers);
ObjectifyService.register(car.getClass());
ObjectifyService.ofy().save().entity(car).now();
}
}
Looking up the entity in the datastore you get this information:
Although the passengers field has the annotation #Unindex it will be indexed, as one can see in the google "Datastore". Why does the annotation #Unindex has no effect in this example???
This is unrelated to Objectify and appears to be some new quirk of the datastore. It might just be a display glitch in the UI. Is it causing problems?
With the code you posted, Objectify will call Entity.saveUnindexedProperty() on the passengers field (even without the #Unindex annotation). But even if Objectify tried to index it, historically you can't index embedded objects, so it's unclear what it means to index a list of them. Maybe Google is rolling out some new behavior and they haven't got the GUI working correctly yet? Or maybe there is a bug in their save behavior?
If you want to be a good citizen, create a simple test case with the low level API (an Entity that contains a property of type List<EmbeddedEntity>), verify that this same behavior occurs, and file a bug in the GAE issue tracker.

How Mybatis (iBatis) read my private variable?

I was wondering how Mybatis get the private variable in Java.
For example:
Let's say we have a Java class called Foo:
public class Foo{
private int foolID;
public Foo(int foolID){
this.foolID = foolID;
}
}
And let's create XML mapper for insert.
<insert id="insert" parameterType="Foo">
insert into foo_table (id)
values (#{foolID});
</insert>
Let's say there are FooDAO java class and FooMapper java interface for this insert.
My question is how come foolID is readable even without Getter (Even if there is a getter method for foolID, I never specify what the getter is...). It seems like magic to me, and I know there is no magic for programming... :)
The only way I can think of is reflection.
Thanks for your help in advance.
That's correct, reflection is used to access private fields, but only if accessing private fields is not restricted.
Seams like reflection is used heavily not just to access private fields but to invoke setters getters etc.

Is there a #visibility package concept in PHPDoc / PHPStorm?

I have a domain model written in PHP, and some of my classes (entities inside an aggregate) have public methods, which should never be called from outside the aggregate.
PHP does not have the package visibility concept, so I'm wondering if there is some kind of standardized way to define #package and #visibility package in the docblocks, and to have a static analysis tool that would report violations of the visibility scope.
I'm currently trying out PHPStorm, which I've found very good so far, so I'm wondering if this software has support for this feature; if not, do you know any static code analysis tool that would?
The closest parallel to this line of thinking that I see in PHP's capability is using "protected" scope rather than public for these kinds of methods. Granted, that requires using inheritance to grant access to the protected items. In my years of managing phpDocumentor, I've never encountered anything else that attempts to mimic that kind of "package scope" that I remember from my Java days.
If the entities within your aggregate root should not be modifiable without going through the aggregate root, then the only means you have to control that is making the entity a private or protected member so that all modifications to the entity have to go through the aggregate.
class RootEntity {
private $_otherEntity;
public function DoSomething() {
$this->_otherEntity->DoSomething();
}
public function setOtherEntity( OtherEntity $entity ) {
$this->_otherEntity = $entity;
}
}
Someone can still always do:
$otherEntity = new OtherEntity();
$otherEntity->DoSomethingElse();
$rootEntity->setOtherEntity($otherEntity);
Though, I guess you could use the magic __call() method to prohibit setting of the _otherEntity anywhere except during construction. This falls under total hack category :)
class RootEntity {
private $_otherEntity;
private $_isLoaded = false;
public function __call( $method, $args ) {
$factoryMethod = 'FactoryOnly_'.$method;
if( !$this->_isLoaded && method_exists($this,$factoryMethod) {
call_user_func_array(array($this,$factoryMethod),$args
}
}
public function IsLoaded() {
$this->_isLoaded = true;
}
protected function FactoryOnly_setOtherEntity( OtherEntity $otherEntity ) {
$this->_otherEntity = $otherEntity;
}
}
So, from there, when you build the object, you can call $agg->setOtherEntity($otherEntity) from your factory or repository. Then when you are done building the object, call IsLoaded(). From there, nobody else will be able to introduce a new OtherEntity into the class and will have to use the publicly available methods on your aggregate.
I'm not sure if you can call that a "good" answer, but it's the only thing I could think of to truly limit access to an entity within an aggregate.
[EDIT]: Also, forgot to mention...the closest for documentation is that there is an #internal for phpdoc:
http://www.phpdoc.org/docs/latest/for-users/tags/internal.html
I doubt that it will modify the IDE's code completion, however. Though, you could probably make a public function/property but label it as "#access private" with phpdoc to keep it from being in code completion.
So far, PHPStorm does not seem to provide this feature.

Displaying Mutable PostgreSQL Arrays in the NetBeans Master/Detail Sample Form using JPA 1.0

Some Background
I have a game database with a table called Games that has multiple attributes and one called Genres. The Genres attribute is defined as an integer[] in PostgreSQL. For the sake of simplicity, I'm not using any foreign key constraints, but essentially each integer in this array is a foreign key constraint on the id attribute in the Genres table. First time working with the NetBeans Master/Detail Sample Form and Java persistence and it's been working great so far except for 1 thing. I get this error when the program tries to display a column that has a 1-dimensional integer array. In this example, the value is {1, 11}.
Exception Description: The object [{1,11}], of class [class org.postgresql.jdbc3.Jdbc3Array], from mapping [oracle.toplink.essentials.mappings.DirectToFieldMapping[genres-->final.public.games.genres]] with descriptor [RelationalDescriptor(finalproject.Games --> [DatabaseTable(final.public.games)])], could not be converted to [class [B].
Exception [TOPLINK-3002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ConversionException
My Research
From what I've been able to read, it looks like PostgreSQL arrays need something special done to them before you can display and edit them in this template. By default, the sample form uses TopLink Essentials (JPA 1.0) as its persistence library, but I can also use Hibernate (JPA 1.0).
Here is the code that needs to be changed in some way. From the Games.java file:
#Entity
#Table(name = "games", catalog = "final", schema = "public")
#NamedQueries({
// omitting named queries
#NamedQuery(name = "Games.findByGenres", query = "SELECT g FROM Games g WHERE g.genres = :genres")
})
public class Games implements Serializable {
#Transient
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
private static final long serialVersionUID = 1L;
// omitting other attributes
#Column(name = "genres")
private Serializable genres;
// omitting constructors and other getters/setters
public Serializable getGenres() {
return genres;
}
public void setGenres(Serializable genres) {
Serializable oldGenres = this.genres;
this.genres = genres;
changeSupport.firePropertyChange("genres", oldGenres, genres);
}
} // end class Games
Here are also some of the sites that might have the solution that I'm just not understanding:
https://forum.hibernate.org/viewtopic.php?t=946973
http://blog.xebia.com/2009/11/09/understanding-and-writing-hibernate-user-types/
// omitted hyperlink due to user restriction
Attempted Solutions
I'm able to get the data to display if I change the type of genres to String, but it is immutable and I cannot edit it. This is what I changed to do this:
#Column(name = "genres")
private String genres;
public String getGenres() {
return genres;
}
public void setGenres(String genres) {
String oldGenres = this.genres;
this.genres = genres;
changeSupport.firePropertyChange("genres", oldGenres, genres);
}
I also attempted to create a UserType file for use with Hibernate (JPA 1.0), but had no idea what was going wrong there.
I also attempted to use the #OneToMany and other tags, but these aren't working probably because I'm not using them properly.
What I'm Looking For
There has to be a simple way to get this data to display and make it editable, but since I'm completely new to persistence, I have no idea what to do.
The effort put into your question shows. Unfortunately JPA does not currently support PostgreSQL arrays. The fundamental problem is that arrays are not frequently used in many other databases frequently and so heavy reliance on them is somewhat PostgreSQL specific. Thus you can expect that general cross-db persistence API's are not generally going to support them well if at all. JPA is no exception, having currently no support for PostgreSQL arrays.
I have been looking at writing my own persistence API in Java that would support arrays, but it hasn't happened yet, would be PostgreSQL-only when written, and would be based on a very different principle than JPA and friends.

Getting column length from Hibernate mappings?

To validate data I am receiving I need to make sure that the length is not going to exceeded a database column length. Now all the length information is stored in the Hibernate mapping files, is there anyway to access this information programmatically?
You can get to it but it's not easy. You might want to do something like below at startup and store a static cache of the values. There are a lot of special cases to deal with (inheritance, etc), but it should work for simple single-column mappings. I might have left out some instanceof and null checks.
for (Iterator iter=configuration.getClassMappings(); iter.hasNext();) {
PersistentClass persistentClass = (PersistentClass)iter.next();
for (Iterator iter2=persistentClass.getPropertyIterator(); iter2.hasNext();) {
Property property = (Property)iter2.next();
String class = persistentClass.getClassName();
String attribute = property.getName();
int length = ((Column)property.getColumnIterator().next()).getLength();
}
}
Based on Brian's answer, this is what I ended up doing.
private static final Configuration configuration = new Configuration().configure();
public static int getColumnLength(String className, String propertyName) {
PersistentClass persistentClass = configuration.getClassMapping(className);
Property property = persistentClass.getProperty(propertyName);
int length = ((Column) property.getColumnIterator().next()).getLength();
return length;
}
This appears to be working well. Hope this is helpful to anyone who stumbles upon this question.
My preferred development pattern is to base the column length on a constant, which can be easily referenced:
class MyEntity {
public static final int MY_FIELD_LENGTH = 500;
#Column(length = MY_FIELD_LENGTH)
String myField;
...
}
Sometimes it may be problem to get the Configuration object (if you are using some application framework and you are not creating session factory by yourself using the Configuration).
If you are using for example Spring, you can use the LocalSessionFactoryBean (from your applicationContext) to obtain Configuration object. Then obtaining of column length is just piece of cake ;)
factoryBean.getConfiguration().getClassMapping(String entityName) .getTable().getColumn(Column col).getLength()
However, when I try to access the LocalSessionFactoryBean, I take a class cast exception
LocalSessionFactoryBean factoryBean = (LocalSessionFactoryBean) WebHelper.instance().getBean("sessionFactory");
exception:
org.hibernate.impl.SessionFactoryImpl cannot be cast to org.springframework.orm.hibernate3.LocalSessionFactoryBean
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean>
This seems devious....
EDIT: found the answer. You need to use an ampersand in front of the bean name string
LocalSessionFactoryBean factoryBean = (LocalSessionFactoryBean) WebHelper.instance().getBean("&sessionFactory");
see this Spring forum post

Resources