GWT with JPA and Gilead example - gwt

Can someone please provide me an example of GWT + JPA + Gilead, I can't seem to find anything on Google with this topic.
Thanks
Thanks Maksim,
I'm not using this in an EJB server but Tomcat. I understand the step you've pointed out above but not sure on how to do the next step which is to set up PersistentBeanManager and send my object over the wire.
Here is what I have thus far but I haven't got a chance to test if this works yet. If you see a problem with this let me know, thanks.
private HibernateJpaUtil gileadUtil = new HibernateJpaUtil();
private static final EntityManagerFactory factory =
Persistence.createEntityManagerFactory("MyPersistentUnit");
public MyServlet() {
gileadUtil.setEntityManagerFactory(factory);
PersistentBeanManager pbm = new PersistentBeanManager();
pbm.setPersistenceUtil(gileadUtil);
pbm.setProxyStore(new StatelessProxyStore());
setBeanManager(pbm);
Book book = new Book();
Book cloned = (Book) pbm.clone(book);
//send the cloned book over the wire
}

I tried to set up my project very similar and also ran into the hibernate exception. I figured out that when using JPA I need to initialize the HibernateJPAUtil with the EntityManagerFactory. When I did this it worked. This changes your first two lines of code to:
public class MyServiceImpl extends PersistentRemoteService implements MyService {
public MyServiceImpl() {
final EntityManagerFactory emf = Persistence.createEntityManagerFactory("MA");
final PersistentBeanManager persistentBeanManager = new PersistentBeanManager();
persistentBeanManager.setPersistenceUtil(new HibernateJpaUtil(emf)); // <- needs EMF here
persistentBeanManager.setProxyStore(new StatelessProxyStore());
setBeanManager(persistentBeanManager);
}
#Override // from MyService
public Stuff getStuff() {
// no need for clone/merge here, as Gilead's GWT PersistentRemoteService does this for us
...
return stuff;
}
}
Also I used net.sf.gilead.pojo.java5.legacy.LightEntity as base class for all my entities (note the java5.legacy package).

Entity:
//imports
#Entity
public class Book extends LightEntity implements Serializable {
private static final long serialVersionUID = 21L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
#Lob
private String description;
#ManyToMany(cascade = CascadeType.ALL)
private List<Author> author;
// Getters and setters
#Override
public int hashCode() {
int hash = 0;
hash += (getId() != null ? getId().hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Book)) {
return false;
}
Course other = (Book) object;
if ((this.getId() == null && other.getId() != null) || (this.getId() != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
}
The Book object looks same.
Then use it as regular EJB on your server and as regular DTO's on your client.
Don't forget to add Gilead's libraries to your project.

Hope this blog will help you.
http://zawoad.blogspot.com/2010/06/google-app-engine-jdo-and-gxtext-gwt.html
This is not a direct a example of what you want but the approach should be like this. We followed the same approach in our project with GWT+JPA+EJB. to send your object over the wire you need a Data Transfer Object (DTO). Convert this DTO to Entity object and do whatever you want to do.

Related

Dynamic injection using #SpringBean in wicket

I have a form that based on collected information generates a report. I have multiple sources from which to generate reports, but the form for them is the same. I tried to implement strategy pattern using an interface implementing report generator services, but that led to wicket complaining about serialization issues of various parts of the report generator. I would like to solve this without duplicating the code contained in the form, but I have not been able to find information on dynamic injection with #SpringBean.
Here is a rough mock up of what I have
public class ReportForm extends Panel {
private IReportGenerator reportGenerator;
public ReportForm(String id, IReportGenerator reportGenerator) {
super(id);
this.reportGenerator = reportGenerator;
final Form<Void> form = new Form<Void>("form");
this.add(form);
...
form.add(new AjaxButton("button1") {
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target)
{
byte[] report = reportGenerator.getReport(...);
...
}
});
}
}
If I do it this way, wicket tries to serialize the concrete instance of reportGenerator. If I annotate the reportGenerator property with #SpringBean I receive Concrete bean could not be received from the application context for class: IReportGenerator
Edit: I have reworked implementations of IRerportGenerator to be able to annotate them with #Component and now I when I use #SpringBean annotation I get More than one bean of type [IReportGenerator] found, you have to specify the name of the bean (#SpringBean(name="foo")) or (#Named("foo") if using #javax.inject classes) in order to resolve this conflict. Which is exactly what I don't want to do.
I think the behavior you're trying to achieve can be done with a slight workaround, by introducing a Spring bean that holds all IReportGenerator instances:
#Component
public class ReportGeneratorHolder {
private final List<IReportGenerator> reportGenerators;
#Autowired
public ReportGeneratorHolder(List<IReportGenerator> reportGenerators) {
this.reportGenerators = reportGenerators;
}
public Optional<IReportGenerator> getReportGenerator(Class<? extends IReportGenerator> reportGeneratorClass) {
return reportGenerators.stream()
.filter(reportGeneratorClass::isAssignableFrom)
.findAny();
}
}
You can then inject this class into your Wicket page, and pass the desired class as a constructor-parameter. Depending on your Spring configuration you might need to introduce an interface for this as well.
public class ReportForm extends Panel {
#SpringBean
private ReportGeneratorHolder reportGeneratorHolder;
public ReportForm(String id, Class<? extends IReportGenerator> reportGeneratorClass) {
super(id);
IReportGenerator reportGenerator = reportGeneratorHolder
.getReportGenerator(reportGeneratorClass)
.orElseThrow(IllegalStateException::new);
// Form logic omitted for brevity
}
}
As far as I am able to find, looking through documentation and even the source for wicket #SpringBean annotation, this isn't possible. The closest I got is with explicitly creating a proxy for a Spring bean based on class passed. As described in 13.2.4 Using proxies from the wicket-spring project chapter in Wicket in Action.
public class ReportForm extends Panel {
private IReportGenerator reportGenerator;
private Class<? extends IReportGenerator> classType;
private static ISpringContextLocator CTX_LOCATOR = new ISpringContextLocator() {
public ApplicationContext getSpringContext() {
return ((MyApplication)MyApplication.get()).getApplicationContext();
}
};
public ReportForm(String id, Class<? extends IReportGenerator> classType) {
super(id);
this.classType = classType;
final Form<Void> form = new Form<Void>("form");
this.add(form);
...
form.add(new AjaxButton("button1") {
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target)
{
byte[] report = getReportGenerator().getReport(...);
...
}
});
}
private <T> T createProxy(Class<T> classType) {
return (T) LazyInitProxyFactory.createProxy(classType, new
SpringBeanLocator(classType, CTX_LOCATOR));
}
private IReportGenerator getReportGenerator() {
if (reportGenerator = null) {
reportGenerator = createProxy(classType);
}
return reportGenerator;
}
}

Why `spring-data-jpa` with `spring-data-cassandra` won't create cassandra tables automatically?

I'm using spring-data-cassandra:3.1.9 and the properties looks like :
spring:
data:
cassandra:
keyspace-name: general_log
session-name: general_log
local-datacenter: datacenter1
schema-action: CREATE
Cassandra version: apache-cassandra-4.0.1
spring-boot: 2.4.7
spring-data-jpa: 2.4.9
spring-jdbc: 5.3.8
spring-orm: 5.3.8
My entity looks like:
#ApiModel(description = "Audit log")
#Entity
#Table(name = "audit_log")
#org.springframework.data.cassandra.core.mapping.Table("audit_log")
public class AuditLogPO implements Serializable {
#PrimaryKeyClass
public static class Id implements Serializable {
private static final long serialVersionUID = 1L;
#ApiModelProperty(value = "业务标识")
#Column(name = "business_key")
#PrimaryKeyColumn(ordinal = 1, ordering = Ordering.ASCENDING)
private String businessKey;
// setters & getters ...
}
#javax.persistence.Id
#PrimaryKey
#org.springframework.data.annotation.Id
#Transient
private Id id;
#ApiModelProperty(value = "业务分区")
#Column(name = "business_partition")
#org.springframework.data.cassandra.core.mapping.Column(value = "business_partition")
private String businessPartition;
// getters & setters ...
}
After running this application, table audit_log will not be created automatically.
Actually, after digging into the source code located in spring-data-cassandra:3.1.9, you can check the implementation:
org.springframework.data.cassandra.config.SessionFactoryFactoryBean#performSchemaAction
wich implementation as following:
protected void performSchemaAction() throws Exception {
boolean create = false;
boolean drop = DEFAULT_DROP_TABLES;
boolean dropUnused = DEFAULT_DROP_UNUSED_TABLES;
boolean ifNotExists = DEFAULT_CREATE_IF_NOT_EXISTS;
switch (this.schemaAction) {
case RECREATE_DROP_UNUSED:
dropUnused = true;
case RECREATE:
drop = true;
case CREATE_IF_NOT_EXISTS:
ifNotExists = SchemaAction.CREATE_IF_NOT_EXISTS.equals(this.schemaAction);
case CREATE:
create = true;
case NONE:
default:
// do nothing
}
if (create) {
createTables(drop, dropUnused, ifNotExists);
}
}
which means you have to assign CREATE to schemaAction if the table has never been created. And CREATE_IF_NOT_EXISTS dose not work.
Unfortunately, we've not done yet.
SessionFactoryFactoryBean#performSchemaAction will be invoked as expected, however tables are still not be created, why?
It is because Spring Data JPA will add entities in org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean#afterPropertiesSet(org.springframework.data.mapping.context.AbstractMappingContext#addPersistentEntity(org.springframework.data.util.TypeInformation<?>)). But performSchemaAction method will be invoked in SessionFactoryFactoryBean. And all of these two FactoryBeans do not have an order and we do not know who will be firstly invoked.
Which means if SessionFactoryFactoryBean#afterPropertiesSet has been invoked firstly, probably no Entity is already there. In this circumstance, no tables will be created automatically for sure.
And how to create these tables automatically?
One solution is that you can invoke SessionFactoryFactoryBean#performSchemaAction in a bean of ApplicationRunner manually.
First of all, let's create another class extends from SessionFactoryFactoryBean as:
public class ExecutableSessionFactoryFactoryBean extends SessionFactoryFactoryBean {
#Override
public void createTables(boolean drop, boolean dropUnused, boolean ifNotExists) throws Exception {
super.createTables(drop, dropUnused, ifNotExists);
}
}
Next we should override org.springframework.data.cassandra.config.AbstractCassandraConfiguration#cassandraSessionFactory as:
#Override
#Bean
#Primary
public SessionFactoryFactoryBean cassandraSessionFactory(CqlSession cqlSession) {
sessionFactoryFactoryBean = new ExecutableSessionFactoryFactoryBean();
// Initialize the CqlSession reference first since it is required, or must not be null!
sessionFactoryFactoryBean.setSession(cqlSession);
sessionFactoryFactoryBean.setConverter(requireBeanOfType(CassandraConverter.class));
sessionFactoryFactoryBean.setKeyspaceCleaner(keyspaceCleaner());
sessionFactoryFactoryBean.setKeyspacePopulator(keyspacePopulator());
sessionFactoryFactoryBean.setSchemaAction(getSchemaAction());
return sessionFactoryFactoryBean;
}
Now we can create an ApplicationRunner to perform the schema action:
#Bean
public ApplicationRunner autoCreateCassandraTablesRunner() {
return args -> {
if (SchemaAction.CREATE.name().equalsIgnoreCase(requireBeanOfType(CassandraProperties.class).getSchemaAction())) {
sessionFactoryFactoryBean.createTables(false, false, true);
}
};
}
please refer this doc https://docs.spring.io/spring-data/cassandra/docs/4.0.x/reference/html/#cassandra.schema-management.initializing.config
But you still need to create keyspace before excuting the following codes:
#Configuration
public class SessionFactoryInitializerConfiguration extends AbstractCassandraConfiguration {
#Bean
SessionFactoryInitializer sessionFactoryInitializer(SessionFactory sessionFactory) {
SessionFactoryInitializer initializer = new SessionFactoryInitializer();
initializer.setSessionFactory(sessionFactory);
ResourceKeyspacePopulator populator = new ResourceKeyspacePopulator();
populator.setSeparator(";");
populator.setScripts(new ClassPathResource("com/myapp/cql/db-schema.cql"));
initializer.setKeyspacePopulator(populator);
return initializer;
}
// ...
}
You can also specify this behavior in your application.yml:
spring:
data:
cassandra:
schema-action: create-if-not-exists
Although, you will need to create the keyspace (with appropriate data center / replication factor pairs) ahead of time.

Why Lazy Collections do not work with JavaFX getters / setters?

I experienced poor performance when using em.find(entity, primaryKey).
The reason seems to be that em.find() will also load entity collections, that are annotated with FetchType.LAZY.
This small test case illustrates what I mean:
public class OriginEntityTest4 {
[..]
#Test
public void test() throws Exception {
final OriginEntity oe = new OriginEntity("o");
final ReferencePeakEntity rpe = new ReferencePeakEntity();
oe.getReferencePeaks().add(rpe);
DatabaseAccess.onEntityManager(em -> {
em.persist(oe);
em.persist(rpe);
});
System.out.println(rpe.getEntityId());
DatabaseAccess.onEntityManager(em -> {
em.find(OriginEntity.class, oe.getEntityId());
});
}
}
#Access(AccessType.PROPERTY)
#Entity(name = "Origin")
public class OriginEntity extends NamedEntity {
[..]
private final ListProperty<ReferencePeakEntity> referencePeaks =
referencePeaks =
new SimpleListProperty<>(FXCollections.observableArrayList(ReferencePeakEntity.extractor()));
#Override
#OneToMany(mappedBy = "origin", fetch = FetchType.LAZY)
public final List<ReferencePeakEntity> getReferencePeaks() {
return this.referencePeaksProperty().get();
}
public final void setReferencePeaks(final List<ReferencePeakEntity> referencePeaks) {
this.referencePeaksProperty().setAll(referencePeaks);
}
}
I cannot find any documentation on that, my question is basically how can I prevent the EntityManager from loading the lazy collection?
Why I need em.find()?
I use the following method to decide whether I need to persist a new entity or update an existing one.
public static void mergeOrPersistWithinTransaction(final EntityManager em, final XIdentEntity entity) {
final XIdentEntity dbEntity = em.find(XIdentEntity.class, entity.getEntityId());
if (dbEntity == null) {
em.persist(entity);
} else {
em.merge(entity);
}
}
Note that OriginEntity is a JavaFX bean, where getter and setter delegate to a ListProperty.
Because FetchType.LAZY is only a hint. Depending on the implementation and how you configured your entity it will be able to do it or not.
Not an answer to titles question but maybe to your problem.
You can use also em.getReference(entityClass, primaryKey) in this case. It should be more efficient in your case since it just gets a reference to possibly existing entity.
See When to use EntityManager.find() vs EntityManager.getReference()
On the other hand i think your check is perhaps not needed. You could just persist or merge without check?
See JPA EntityManager: Why use persist() over merge()?

Spring MVC usage of form:radiobuttons to bind data (whole object not only one value)

I have a problem with sending data to backend by POST from my JSP using construction:
<form:radiobuttons path="pvClCategory" items="${categoryList}" itemLabel="clcaCategory"/>
After sumbit my Jboss (version 5) displays:
HTTP Status 400 - description: The request sent by the client was syntactically incorrect ().
I don't know how to see sent request. When I am using construction below everything works fine but I do not want to bind only one value from object, but whole object:
<form:radiobuttons path="pvClCategory.clcaCategory" items="${categoryList}" itemValue="clcaCategory" itemLabel="clcaCategory"/>
So, the first form construction (with binding whole object) cause me a problem. Form is initialised properly it means that radio options are correctly displayed and correct value is selected on jsp site. But problem appears when I want to submit the form, i receive error (HTTP Status 400 request sent by client was syntactically incorrect). Any idea why? What I am doing wrong?
My code:
I have one entity class Violation with field named pvClCategory type of ClCategory
#Entity
#Table(name="PV_VIOLATIONS")
public class Violation implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="VIOL_ID")
private Long id;
#ManyToOne
#JoinColumn(name="VIOL_CLCA_ID")
private ClCategory pvClCategory;
/* others fields and getters/setters */
}
My ClCategory entity class which is needed to bind it to Violation.pvClCategory field:
#Entity
#Table(name="PV_CL_CATEGORIES")
#Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
public class ClCategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="CLCA_ID")
private long clcaId;
#Column(name="CLCA_CATEGORY")
private String clcaCategory;
#OneToMany(mappedBy="pvClCategory")
private List<Violation> pvViolations;
public ClCategory() {
}
public long getClcaId() {
return this.clcaId;
}
public void setClcaId(long clcaId) {
this.clcaId = clcaId;
}
public String getClcaCategory() {
return this.clcaCategory;
}
public void setClcaCategory(String clcaCategory) {
this.clcaCategory = clcaCategory;
}
public List<Violation> getPvViolations() {
return this.pvViolations;
}
public void setPvViolations(List<Violation> pvViolations) {
this.pvViolations = pvViolations;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (clcaId ^ (clcaId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ClCategory other = (ClCategory) obj;
if (clcaId != other.clcaId)
return false;
return true;
}
}
This Violation class is used in my form in commandName property as follows (file name: v.jsp):
<form:form action="../update" method="post" commandName="violation">
<form:radiobuttons path="pvClCategory" items="${categoryList}" itemLabel="clcaCategory"/>
<!-- other fields -->
<button type="submit" value="Apply Changes" class="button-default" >Apply</button>
</form:form>
My controller:
#Controller
#RequestMapping("/viol")
public class ViolationController {
#RequestMapping("edit/{violationId}")
public String edit(#PathVariable("violationId") long id, Map<String, Object> map) {
Violation violation = violationService.getViolation(id);
map.put("violation",violation);
map.put("categoryList", adminService.listCategories());
return "v";
}
}
As I understand in the construction form:radiobuttons path="" items="" the path is property for data binding so whole object from delivered list in items should be binded to it. I put in items List of my categories which are objects of type ClCategory. After submit error appears.
When i use form:radiobuttons path="pvClCategory.clcaCategory" items="${categoryList}" itemValue="clcaCategory" itemLabel="clcaCategory" to bind only String value from object in items (in both cases is used the same object list of type ClCategory) then the form is correctly submited but I do not want to bind only one value of objecte but whole object. Could you help me what am I doing wrong?

gwt rpc serialize generic class

I need to pass a class object through the gwt rpc connection as a generic but it seems that rpc does not cooperate with it. The class is serialized using the java.io.Serializable. I have checked it using the gwt IsSerializable but i still have the error.
Here is my code
MySource.java
#SuppressWarnings("serial")
#PersistenceCapable
#Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public abstract class MySource implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
private String userId;
#Persistent
private String title;
#Persistent
private String description;
#Persistent
private String blobKey;
#Persistent
private String youtubeLink;
#Persistent
private String personalLink;
#Persistent
private Date submitedDate;
#Persistent
private float price;
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getBlobKey() {
return blobKey;
}
public void setBlobKey(String blobKey) {
this.blobKey = blobKey;
}
public String getYoutubeLink() {
return youtubeLink;
}
public void setYoutubeLink(String youtubeLink) {
this.youtubeLink = youtubeLink;
}
public String getPersonalLink() {
return personalLink;
}
public void setPersonalLink(String personalLink) {
this.personalLink = personalLink;
}
public Date getSubmitedDate() {
return submitedDate;
}
public void setSubmitedDate(Date submitedDate) {
this.submitedDate = submitedDate;
}
public Long getId() {
return id;
}
}
AndroidSource.java
#SuppressWarnings("serial")
#PersistenceCapable
public class AndroidSource extends MySource{
public AndroidSource() {
super();
}
}
CategoryBrowseService.java which is the remoteservice model
#RemoteServiceRelativePath("categoryService")
public interface CategoryBrowseService extends RemoteService{
ArrayList<MySource> getSourceList(Class<? extends MySource> classType);
}
CategoryBrowseServiceAsync.java
public interface CategoryBrowseServiceAsync {
void getSourceList(Class<? extends MySource> classType,
AsyncCallback<ArrayList<MySource>> callback);
}
CategoryBrowsePresenter.java where the rpc is called
private void retrieveSources(Class<? extends MySource> classType) {
CategoryBrowseServiceAsync rpcService = GWT.create(CategoryBrowseService.class);
rpcService.getSourceList(classType, new AsyncCallback<ArrayList<MySource>>() {
#Override
public void onFailure(Throwable caught) {
Window.alert("Ooops!!!Sorry!Something went wrong.I am still beta!");
}
#Override
public void onSuccess(ArrayList<MySource> result) {
sourceList = result;
display.setSourceContent(sourceList);
}
});
}
CategoryBrowseServiceImpl.java
#SuppressWarnings("serial")
public class CategoryBrowseServiceImpl extends RemoteServiceServlet implements CategoryBrowseService{
private SourceDatastore dataStore;
public CategoryBrowseServiceImpl() {
dataStore = new SourceDatastore();
}
#Override
public ArrayList<MySource> getSourceList(Class<? extends MySource> classType) {
return dataStore.getSources(classType);
}
}
Here is the error that i get.
Compiling module com.sourcebay.SourceBay
Scanning for additional dependencies: file:/home/santaris/workspace/SourceBay/src/com/sourcebay/client/presenter/mybay/browse/CategoryBrowsePresenter.java
Computing all possible rebind results for 'com.sourcebay.client.model.mybay.browse.CategoryBrowseService'
Rebinding com.sourcebay.client.model.mybay.browse.CategoryBrowseService
Invoking generator com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator
Generating client proxy for remote service interface 'com.sourcebay.client.model.mybay.browse.CategoryBrowseService'
[ERROR] java.lang.Class<T> is not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' or 'java.io.Serializable' nor does it have a custom field serializer (reached via java.lang.Class<? extends com.sourcebay.shared.source.MySource>)
[ERROR] java.lang.Class<T> has no available instantiable subtypes. (reached via java.lang.Class<? extends com.sourcebay.shared.source.MySource>)
[ERROR] subtype java.lang.Class<T> is not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' or 'java.io.Serializable' nor does it have a custom field serializer (reached via java.lang.Class<? extends com.sourcebay.shared.source.MySource>)
[ERROR] Errors in 'file:/home/santaris/workspace/SourceBay/src/com/sourcebay/client/presenter/mybay/browse/CategoryBrowsePresenter.java'
[ERROR] Line 75: Failed to resolve 'com.sourcebay.client.model.mybay.browse.CategoryBrowseService' via deferred binding
The paradox is that when i am running my application through the eclipse plugin everything works fine. Could anyone help me please? I have checked to fix the problem through the DTO solution without any success. Moreover i have tried to implement a CustomFieldSerializer as Google suggests without any success too.
Thanks in advance,
Stefanos Antaris
P.S. Sorry for the huge post :-)
Well the problem is that you trying to transport a Class object over the network. I have no idea why it is working in dev mode (I've tried it on local project and it failed), but it shouldn't work. You have to use something else instead of Class name for example String, which will contain a name of class. Theoretically it can work if you create CustomFieldSerializer for Class, but using String instead of Class will be easier.
Classes with persistence annotations can work well on the server side, but if you want to pass its data to the client you must create a plain java serializable class to transport data from server to client.
As noted in the previous answer, persistence annotations are not supported in the client side, as they cannot be translated to equivalent javascript code (and it makes sense since the client doesn't have the responsability of persistence).
It could be that the persistence-related annotations in MySource.java make it implossible to translate to javascript. Try removing the annotations to see if it's related. Also make sure that MySource.java is in a package declared as translatable in the module xml file ("source" element).
Try using implements Serializable for defining you class.
I mean like this:
public class AndroidSource extends MySource implements Serializable{
public AndroidSource() {
super();
}
}
Your RPC Services must deal just with Serializable Objects. Domain classes are not translatable to JavaScript So GWT can't send and receive via network (RPC Protocole) such objects. You need to create DTO classes (wich shadows domain class) implementing java.io.Serializable and then reconfigure all your RPC Service to use in input DTOs and output DTOs. Good Luck for your project.