GWT + GAE datastore Key and Text Java Error - java

I would like to create an application that saves and retrieves records to the GAE server. I followed the tutorial "Deploying to Google App Engine" http://code.google.com/webtoolkit/doc/latest/tutorial/appengine.html to get started.
I have the StockWatcher application working now, but in my application I need to store a String that can be large (>10KB). I read that I can't use a Java String type to store large strings and need to use the Text data type instead.
I think by Text, they mean: com.google.appengine.api.datastore.Text, but it would be nice to confirm this is correct. ???
Regardless, I can't get Text to work. After some research it appears both the types Key and Text can only be used in the server code and not the client code. It seems that this is because the source code is not available for these classes and GWT needs the source to create the JavaScript code on the client's computer. At least that my current working hypothesis as to why I'm getting the following errors:
21:52:52.823 [ERROR] [myapp] Line 15: The import com.google.appengine.api.datastore cannot be resolved
21:52:52.951 [ERROR] [myapp] Line 103: Key cannot be resolved to a type
21:52:53.011 [ERROR] [myapp] Line 106: Text cannot be resolved to a type
I use the following fields in a class in a shared folder.
shared/MyDataRecord
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;
#Persistent
private Text description;
MyDataRecord class in a shared folder because I wanted to use to send back all the fields in one get method return rather than multiple individual field get methods. Here's how I use MyDataRecord class in my server/DataServiceImpl.java class
public class DataServiceImpl extends RemoteServiceServlet implements DataService
{
...
#Override
public MyDataRecord getDataRecord() throws NotLoggedInException
{
...
I've seen some posted solutions suggest using non-standard, 3rd party libraries, like http://www.resmarksystems.com/code/. I couldn't get this one installed, but even if I could, I'd prefer a different solution. Storing Text must be such a common task that I'd prefer to solve this using what is considered a standard solution.
I could change my code to return each field in multiple get methods instead of an single return of a MyDataRecord instance. However, even if that works, that would be significantly more work and more difficult to maintain over time. However, if this is what is normally expected, then that's what I'll do.
I'd like to solve this using what is considered best practices by GWT and GAE. A simple example or tutorial would go a long way, but I can't find one.
Are there example programs/tutorials that show what GWT considers best practices for storing and retrieving large strings?
I am a newbie with both GWT and GAE (as well as web development), please consider this in any responses, thanks.
No Snark Please

The serializable POJO. Note the NotPersistent annotation for description
package com.my.project.shared;
#PersistenceCapable(identityType=IdentityType.APPLICATION,detachable="true")
public class MyParent implements Serializable {
#PrimaryKey
#Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
private Long id;
#NotPersistent //Note the NotPersistent annotation. GAE won't persist this value in big table
private String description;
}
The second POJO. Notice the package
package com.my.project.server;
#PersistenceCapable(identityType=IdentityType.APPLICATION,detachable="true")
public class MyChild implements Serializable{//Not really required to implement Serializable
#PrimaryKey
#Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
private Long parentID;//Reference to the MyParent
#Persistent
private Text description;//The actual value of the description variable.
}
Notice the parent ID mapped in the child. While retrieving you will need to identify which child belongs to which parent.
In pseudo code
1) Load parent from DB
2) Identify child for this parent, and load it
3) Convert child.description->parent.description
4) Now you have a fully constructed parent POJO which is serializable. Send it to the UI
Just reverse the procedure on the way back from UI to GAE.

1) Define a NotPersistent field in your serializable POJO private String description
2) Define a new POJO on the server side which will have private Text description
3) When you persist/load the original POJO, retrieve the new POJO and populate the String description from the Text description

Related

Read javax annotations with custom doclet

I got a bunch of DTO's which are not commented at all. However, there are comments in the SQL-Database. I can get these comments by sending a query and then retrieving the ResultSet.
My task is to create a javadoc-API (as HTML) with the comments from the SQL-Database in order to make the codebase better understandable.
After asking about this task already HERE, I tried to looked into creating my own doclet. I then wrote my own doclet by rewriting the Standard-, Abstract- and HtmlDoclet from Java.Tools. My results are working fine and I can create javadoc html pages WITH the comments from the database.
HOWEVER its a massive hack imho. There are two main tasks that need to be done in order to get the Database comments.
know the table name
know the column name
How it should be done: (which is what I want to ask - How do I implement it like this?)
For 1. : Find the #Table annotation. Read name = "tablename".
For 2. : For each variable:
Is there a #Column annotation ? return "columnName" : return ""
How I do it right now:
For 1. : I read the RootDoc.name() variable and then read the String char by char. Find a capital letter. Insert '_'. And at the end, turn everything .toUpperCase(). So "testFile" turns into "TEST_FILE".
This sometimes does not work. If you read carefully in the example class. Its name is "SaklTAdrkla" but the Databasetable name is SAKL_T_ADRKLAS. Parsing the name from RootDoc.name() would result in "SAKL_T_ADRKLA" which is missing the character 'S' at the end, therefore it wont find the table in the database.
For 2. : I get all Fields from the ClassDoc. I then parse Field.name() the same way I parsed the RootDoc.name() variable.
This wont work for the same reason as 1.; but also because some fieldnames are not the same as their mapped names. In the example Class - field sakgTAklgrpAklAkgid is mapped in the database as AKL_AKGID
I am able to find the Annotation itselfe by calling FieldDoc.annotations(). But thats ONLY the annotation without the String (name = "xyz") which is the most important part for me!
I have found the Jax-Doclet, which can parse the javax annotations. However after downloading the jar-source file and implementing the java files, there are numerous dependency issues which are not resolvable because the referenced classes no longer exist in java 8 tools.jar.
Is there another solution, that is capable of reading the javax annotations?
Can I implement something into my doclet so it can read the javax annotations?
Edit:
I found out you can call .elementValues() on the AnnotationDesc class which I can get from FieldDoc.annotations(). However I always get a com.sun.jdi.ClassNotLoadedException Type has not been loaded occurred while retrieving component type of array. To fix it I manually load the classes AnnotationDesc and AnnotationDesc.ElementValuePair by calling Class.forName(). However now the Array with the elementValuePairs is empty..?
Example class:
/**
* The persistent class for the SAKL_T_ADRKLAS database table.
*/
#Entity
#IdClass(SaklTAdrklaPK.class)
#Table(name = "SAKL_T_ADRKLAS")
#NamedQuery(name = "SaklTAdrkla.findAll", query = "SELECT s FROM SaklTAdrkla s")
public class SaklTAdrkla implements Serializable, IModelEntity {
private static final long serialVersionUID = 1L;
#Id #Column(name = "AKL_AKLID") private String aklAklid;
#Id
// uni-directional many-to-one association to SakgTAklgrp
#JsonBackReference(value = "sakgTAklgrpAklAkgid") #ManyToOne #JoinColumn(name = "AKL_AKGID") private SakgTAklgrp sakgTAklgrpAklAkgid;
#Temporal(TemporalType.TIMESTAMP) #Column(name = "AKL_AEND") private Date aklAend;
#Column(name = "AKL_DEFLT") private BigDecimal aklDeflt;
#Column(name = "AKL_SPERRE") private BigDecimal aklSperre;
#Column(name = "AKL_T_BEZ") private String aklTBez;
#Column(name = "AKL_USRID") private String aklUsrid;
public SaklTAdrkla() {
}
It took me quite a while to figure this out now, but I finnally did.
The Problem was that my doclet could find all the annotations, which it displayed in the console as errors.
error: cannot find symbol #Column(name = "TST_USER") private
String tstUser;
What I also found was this message in the lot of errors that got thrown:
error: package javax.persistence does not exist import
javax.persistence.*;
So I imported javax.persistance.jar into my project.
I also added com.fasterxml.jaxkson.annotations.jar into the project since it would also not work without it.
Surprise Surprise! IT WORKS!
I can get all the annotations and annotation values by using annotation.elementValues().
I no longer get an empty Array nor do I get an ClassNotLoadedException.

Load the embedded class directly without the embedding class in Morphia

I've the following two simple classes, which are exemplary for the structure of my problem:
The first class, which embeds the second one
#Entity
public class MyClass {
#Id
private String myClassName;
private String otherField;
#Embedded
private List<MyEmbedded> myEmbeddeds;
}
And the second class which will be embedded:
#Embedded
public class MyEmbedded {
#Id
private String name;
private String some;
private String other;
}
In the real case, both classes have a far more complicated structure, with a lot of more fields and references.
Due to that, i don't want to load the whole MyClass object, as in most cases I only need one specific element from the MyEmbedded list (in most cases with a read-only access).
On the other hand, setting the MyEmbedded class as a simple reference is no option, as we have some complex queries for the MyClass which heavily depend on the myEmbeddeds, which would mean that we would have to execute multiple queries, which is not wanted.
So, the main question is:
How can I load one specific element of the myEmbeddeds list directly as a MyEmbedded-object, without loading the "parent"-object?
Maybe there is a way by using the AggregationPipeline? ( you can define a "target" class in pipeline.aggregate() method and one can find some examples in the tests of morphia as you can see here but i didn't get that working for my case)
You could query MyClass based on attributes of MyEmbedded and then use a projection to only pull myEmbeddeds from the results.

Limiting Fields in JSON Response for REST API?

I am using Spring and Java and implementing REST Based services. I have a set of developers who develop for mobile,iPad and Web too. Consider I have a bean
Class User{
private String Name;
private Integer id;
private String photoURL;
private ArrayList<String> ProjectName;
private ArrayList<String> TechnologyList;
private ArrayList<String> InterestList;
//Getters and setters
}
While the Web Developers need the entire fields and mobile developers just require two fields from it whereas the iPad requires something in between mobile and web.
Since I am using jackson as a parser, is there a way where while requesting to the controller I can specify which all data I require and avoid the others. For example consider I do a GET request like
GET>http://somedomain.com/users?filter=name,id,photoUrl
Which returns me a JSON structure something like
{
"name":"My Name",
"id":32434,
"photoUrl":"/sss/photo.jpg"
}
Sameway if someone asks for some more fields, they could be filtered. Please let me know how this can be done so that my API remains generic and useable for all.
You can achieve what you want but some extra work is necessary. I can offer you two solutions.
1. Return a Map
Simply put every property that is requested into the map.
2. Use Jacksons Object Mapper directly
Jackson lets you set filters that specify which properties are serialized or ignored.
FilterProvider filter = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept(requestedProperties));
String json = objectMapper.writer(filter).writeValueAsString(value);
You can then return the JSON string directly instead of an object.
For both solutions you would ideally write a class that does the job. But if you do that you could as well write your own message converter. You could extend the MappingJackson2HttpMessageConverter, for instance, and overwrite the writeInternal method to suit your needs. That has the big advantage that you don't need to change your controllers.
The straightforward solution is to implement custom Jackson JSON serializer that will get field names that should be serialized from thread local storage and then serialize only fields which names are presented in that context. For other hand, in controller you can grab all allowed fields names from url and store them into thread local context. Hope this helps.

Morphia - change class associated with a collection

I'm trying to phase out an older java codebase that uses MongoDB/Morphia. During this transition, I'd like the new platform to write to the same MongoDB database/collections so that each can live side by side for a little while. That part I'm doing alright with. My issue is that in the new platform, I need a different package/class structure for the objects I'm mapping with morphia than what is currently in the collection.
For instance, in the old platform I've got this class:
package com.foo;
#Entity
public class Bar {
#Id private String id;
private String name;
...
}
In my mongo database, I now have a collection "Bar" and its documents have the className attribute set to "com.foo.Bar". That's all wonderful.
What I'd like to do in the new platform is create a brand new class in a different package to represent that entity, but have it interact with mongo in the same way. I'm hoping to be able to do something like this:
package com.foo.legacy;
#Entity("com.foo.Bar")
public class LegacyBar {
#Id private String id;
private String name;
...
}
I realize the above doesn't work, but if I change the annotation to #Entity("Bar") I don't get any errors, but when I look up entities by id, I always get null back.
So... is there any way for me to have 2 separate VMs with 2 class structures and 2 different configurations of Morpha such that each can write to the same database/collection in the same fashion?
If I change LegacyBar to just "Bar" and create it in a package called "com.foo" then everything works as expected. I would just REALLY prefer to have the flexibility to quarantine all of this legacy data in a semi-clean fashion.
Do you even need the className attribute?
You can disable it with
#Entity(value = "Bar", noClassnameStored = true)
and drop the attribute in the database.
Quoting the official documentation:
Why would you need it?
This is mainly used when storing different
entities in the same collection and reading them back as the base or
super class.
If you don't do this, it should be an easy workaround to allow different package structures.

Command Objects in Spring

I have a command object composed of primitive fields and an object field. How do I bind my form fields to the fields in the object?
I tried doing this but to no avail
<form:form commandName="course" method="POST">
<form:input path="activity.activity"/>
.
.
.
</form:form>
I get this error
org.springframework.beans.NotReadablePropertyException:
Invalid property 'course' of bean class
My Command class is like this
public class Course {
private long id;
private String owner;
private String title;
private List<LearningActivity> activity = new ArrayList<LearningActivity>();
//getters and setters
}
public class LearningActivity {
private long ID;
private String activity;
private String link;
//getters and setters
}
Your list either needs to be pre-populated with as many LearningActivity objects as you plan to refer to (using activity[0], activity[1], etc.) or it needs to be a lazy list. A lazy list is a list that will populate itself with empty objects when a given index is referenced.
A comment indicates that you're trying to use Apache Commons LazyList, which ought to work -- are you missing an import directive? However, as an alternative there is a Spring lazy list implementation called AutoPopulatingList.
Two possible issues here:
activity.activity is invalid (unless your getters do not correspond to your member variables) because Course.activity is a list. You need to address a particular list element - e.g. activity[0].activity. You'll also have to make sure it actually exists.
Have you configured your FormController correctly? Does it pass Course instance to view as it should? Take a look at Spring MVC tutorial for an example.
If after you've fixed #1 and verified that #2 is done correctly the error doesn't go away, please post more details (FormController mapping / source).

Categories

Resources