Objectify throws IllegalArgumentException: No class 'com.app.db.client.model.ProductType' was registered - google-app-engine

I am using Objectify 5.1.7 with Objectify Spring extension in my Spring-MVC application.
Here are my entity classes:
Product.java
#Entity
public class Product extends RelatedDataObject {
#Parent
private Ref<Vendor> vendor;
#Load
private Ref<ProductCategory> productCategory;
#Load
private Ref<ProductType> productType;
#Index
private String nativeId;
private Double costPrice;
private String modelId;
private String serviceLocations;
private Map<String, String> attributes;
public Double getCostPrice() {
return costPrice;
}
public String getModelId() {
return modelId;
}
public String getServiceLocations() {
return serviceLocations;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setCostPrice(Double costPrice) {
this.costPrice = costPrice;
}
public void setModelId(String modelId) {
this.modelId = modelId;
}
public void setServiceLocations(String serviceLocations) {
this.serviceLocations = serviceLocations;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
public void addAttribute(String key, String value) {
if(key == null || value == null) {
throw new IllegalArgumentException("Key or value is null.");
}
if(attributes == null) {
attributes = new HashMap<String, String>();
}
attributes.put(key, value);
}
public ProductCategory getProductCategory() {
return productCategory.get();
}
public ProductType getProductType() {
return productType.get();
}
public String getNativeId() {
return nativeId;
}
public void setNativeId(String nativeId) {
this.nativeId = nativeId;
}
public void setProductCategory(ProductCategory productCategory) {
this.productCategory = Ref.create(productCategory);
}
public void setProductType(ProductType productType) {
this.productType = Ref.create(productType);
}
public Vendor getVendor() {
return vendor.get();
}
public void setVendor(Vendor vendor) {
this.vendor = Ref.create(vendor);
}
public Key<Product> getKeyByParentVendor() {
if (getId() == null) {
throw new IllegalArgumentException("Product id is not set.");
}
if (vendor == null) {
throw new IllegalArgumentException("Parent vendor is not set.");
}
return Key.create(this.vendor.key(), Product.class, getId());
}
}
ProductType.java
#Entity
public class ProductType extends RelatedDataObject {
}
RelatedDataObject.java
public class RelatedDataObject extends DataObject {
private String description;
private boolean approved;
public RelatedDataObject() {
super();
approved = false;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isApproved() {
return approved;
}
public void setApproved(boolean approved) {
this.approved = approved;
}
}
DataObject.java
public class DataObject {
#Id
private String id;
#Index
private String name;
private boolean inactive;
public DataObject() {
super();
inactive = false;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public boolean isInactive() {
return inactive;
}
public void setInactive(boolean inactive) {
this.inactive = inactive;
}
}
And here is my spring bean xml configuration. All my entity classes are inside the package: com.app.db.client.client.model
<bean id="objectifyFactory" class="com.googlecode.objectify.spring.ObjectifyFactoryBean">
<property name="basePackage" value="com.app.db.client.model"/>
</bean>
<bean id="dbClient" class="com.app.db.client.impl.DbClientImpl">
<property name="objectifyFactory" ref="objectifyFactory"/>
</bean>
DBClientImpl.java
public class DbClientImpl implements DbClient {
private ObjectifyFactory objectifyFactory;
public void setObjectifyFactory(ObjectifyFactory objectifyFactory) {
this.objectifyFactory = objectifyFactory;
}
#Override
public <T extends DataObject> void createObject(T object) {
Objectify ofy = objectifyFactory.begin();
ofy.save().entity(object).now();
}
}
When the GAE devserver boots my spring MVC application, all entity classes are loaded. Here are the log messages:
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.Product]
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.ProductCategory]
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.ProductType]
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.Vendor]
When I try to save Product entity:
Product product = new Product();
product.setName("new product");
product.setProductType(productType);
product.setProductCategory(productCategory);
product.setNativeId(productNativeId);
product.setCostPrice(createProductParam.getCostPrice());
dbclient.createObject(product);
I get this error from Objectify:
[INFO] java.lang.IllegalArgumentException: No class 'com.app.db.client.model.ProductType' was registered
[INFO] at com.googlecode.objectify.impl.Registrar.getMetadataSafe(Registrar.java:120)
[INFO] at com.googlecode.objectify.impl.Keys.getMetadataSafe(Keys.java:53)
[INFO] at com.googlecode.objectify.impl.Keys.getMetadataSafe(Keys.java:62)
[INFO] at com.googlecode.objectify.impl.Keys.rawKeyOf(Keys.java:36)
[INFO] at com.googlecode.objectify.impl.Keys.keyOf(Keys.java:29)
[INFO] at com.googlecode.objectify.Key.create(Key.java:62)
[INFO] at com.googlecode.objectify.Ref.create(Ref.java:31)
[INFO] at com.app.db.client.model.Product.setProductType(Product.java:93)
Please help me resolve this problem.

I have got the same Issue and solved as in below steps.
1) Write your own ObjectifyFactoryBean (Just copy from https://github.com/marceloverdijk/objectify-appengine-spring) and update one line in afterPropertiesSet() method.
this.objectifyFactory = new ObjectifyFactory();
// Set the factory to ObjectifyService
ObjectifyService.setFactory(objectifyFactory);
2) Use this to in spring
<bean id="objectifyFactory" class="com.yourcompany.ObjectifyFactoryBean" >
<property name="basePackage" value="com.yourcompany.model" />
</bean>
3) Use objectifyFactory in your DAO classes as spring bean.
4) Add the Filter in your web.xml.
<!-- ObjectifyFilter filter -->
<filter>
<filter-name>objectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>objectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Explanation : I don't know how old version of Objectify work and based on that ObjectifyFactoryBean written, but in latest version of Objectify 5.x it internally use ObjectifyService in Ref operation, which was using the different objectifyFactory instance, So to make it use the same instance of objectifyFactory in whole application, we have set ObjectifyService.setFactory(objectifyFactory) inside our ObjectifyFactoryBean class.
A filter ObjectifyFilter is also require in web application, because this filter will make call to ObjectifyService.begin() for Objectify session, Normally we call ObjectifyService.begin() only when we do Datastore Operation and but is case of like Ref operation, ObjectifyFilter will do this job for us.
Hope this solve the issue!

The spring extension hasn't been updated since 2012 so it's entirely possible that it does not work with current versions of Objectify. I don't know - I would contact the author.
The problem is that your ProductType entity has not been registered. Presumably the spring extension is supposed to do that but isn't.

Like #stickfigure already mentioned this library hasn't been updated for a long time. That said the Objectify version it depends on - and tested with - is 2.2.x.
However from your logging it seems that the entities have been registered.
To verify if it works with the latest Objectify version you could:
clone the lib from https://github.com/marceloverdijk/objectify-appengine-spring
update the objectify version
run the tests
If that works you at least know the lib works with the latest Objectify version.

Related

How do I delete multiple records using REST API

Am new to Springboot, I have develop the resource to delete the record by ID, now I like delete selected multiple records.
Example: I like to delete 3 records out of 10 records in single request
Controller class:
#ApiHeader(
apiOperation = "delete a Content Manage by id",
apiOperationNotes = "delete a Content Manage by id"
)
#PostMapping(value = UriConstants.CONTENT_MANAGE_DELETE)
#ResponseStatus(HttpStatus.OK)
public void deleteContentManage(#PathVariable("content_manage_id") int contentmanageId) {
contentManageService.deleteContentManage(contentmanageId);
}
Service Class:
#Transactional(rollbackFor = Exception.class)
public void deleteContentManage(int contentmanageId) {
Optional<UserContentManage> optional = userContentManageRepository.findById(contentmanageId);
if(!optional.isPresent()){
log.error("Exception occurs while not found content manage ({}) in deletion. ", contentmanageId);
throw new GenericBadException(StaffNotificationExceptionEnum.CONTENT_MANAGE_NOT_FOUND_EXCEPTION);
}
userContentManageRepository.deleteById(contentmanageId);
}
JPA Class:
public interface UserContentManageRepository extends JpaRepository<UserContentManage, Integer> {
}
please suggest me how do I delete selected multiple records.
You can add method in Repository like
#Modifying
#Transactional
#Query("delete from UserContentManagep where u.id in(:integers)")
void deleteByIdIn(List<Integer> integers);
If you have implemented soft delete in project you can do soft delete like below:
#Modifying
#Transactional
#Query("update UserContentManagep u set u.active = false where u.id in(:integers)")
void softDeleteAllIds(List<Integer> integers);
And from service class you can try to call as
public void deleteAllBYIds(List<Integer> integers) {
personRepository.deleteByIdIn(integers);
}
Fully working example:
#RestController
#RequestMapping("/person")
public class PersonController {
private final PersonService personService;
#Autowired
public PersonController(PersonService personService) {
this.personService = personService;
}
#GetMapping
public Iterable<Person> list() {
return personService.list();
}
#PostMapping
public Person create(#RequestBody Person car) {
return personService.save(car);
}
#DeleteMapping
public String delete(#RequestParam("ids") List<Integer> ids) {
System.out.println("deleting");
personService.deleteAllBYIds(ids);
return String.join(",", ids.stream().map(value -> Integer.toString(value)).collect(Collectors.toList()));
}
}
#Getter
#Setter
#ToString
#Entity
#Where(clause = "active = true") // selecting only items which are active
class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private boolean active = true;
}
#Service
class PersonService {
private final PersonRepository personRepository;
#Autowired
PersonService(PersonRepository personRepository) {
this.personRepository = personRepository;
}
#Transactional
public Person save(Person person) {
return personRepository.save(person);
}
#Transactional(readOnly = true)
public Iterable<Person> list() {
return personRepository.findAll();
}
#Transactional(readOnly = true)
public PersonDTO findPersonByName(String name) {
return personRepository.findPersonsByName(name);
}
public void deleteAllBYIds(List<Integer> integers) {
// personRepository.deleteByIdIn(new ArrayList<>(integers));
personRepository.softDeleteAllIds(integers);
System.out.println("deleted adnlakdjakldlas");
}
}
interface PersonDTO {
String getName();
Collection<String> getPersonEvents();
}
#Repository
interface PersonRepository extends CrudRepository<Person, Integer> {
PersonDTO findPersonsByName(String name);
#Modifying
#Transactional
#Query("delete from Person p where p.id in(:integers)")
void deleteByIdIn(List<Integer> integers);
#Modifying
#Transactional
#Query("update Person p set p.active = false where p.id in(:integers)")
void softDeleteAllIds(List<Integer> integers);
}
First of all you need to create a jpa query method that brings all records belong to id.
public interface UserContentManageRepository extends JpaRepository<UserContentManage, Integer> {
List<UserContentManage> findAllById(Integer id);
}
After that you can do deleteAll() operation on List.
#Transactional(rollbackFor = Exception.class)
public void deleteContentManage(int contentmanageId) {
List<UserContentManage> userContentManageList = userContentManageRepository.findAllById(contentmanageId);
if(userContentManageList == null){
log.error("Exception occurs while not found content manage ({}) in deletion. ");
throw new GenericBadException(StaffNotificationExceptionEnum.CONTENT_MANAGE_NOT_FOUND_EXCEPTION);
}
userContentManageRepository.deleteAll(userContentManageList );
}

Hibernate filters are not working for APIs returning single result

I have added Hibernate filters on my entities . These filters are applied on queries which fetch Collection of entity but not applied on queries which fetch single entity. Below is my code.
AOrganization.java
#MappedSuperclass
#FilterDef(name = "OrgFilter", parameters = { #ParamDef(name = "allowedOrgIdList", type = "long") })
#Filter(name = "OrgFilter", condition = "org_id in (:allowedOrgIdList)")
public class AOrganization implements Serializable {
#ManyToOne()
#JoinColumn(name = "org_id", nullable = true)
private Organization organization;
public Organization getOrganization() {
return organization;
}
public void setOrganization(Organization organization) {
this.organization = organization;
}
}
Site.java
#Data
#Entity
#Table(name = "site")
public class Site extends AOrganization{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "site_name")
private String siteName;
#Override
public String toString() {
return "Site [id=" + id + ", siteName=" + siteName + "]";
}
}
SiteService.java
public interface SiteService {
public List<Site> getAllSites();
public List<Site> getSiteBySiteName(String siteName);
public Site updateSiteName(Long id, String siteName);
}
SiteRepository.java
#Repository
public interface SiteRepository extends AOrganizationRepository<Site, Long> {
public List<Site> findBySiteName(String siteName);
public List<Site> findByOrganization_Id(Long orgId);
}
AOrganizationRepository.java
#NoRepositoryBean
public interface AOrganizationRepository<T, ID extends java.io.Serializable> extends CrudRepository<T, ID> {
}
SiteServiceImpl.java
#Service
public class SiteServiceImpl implements SiteService {
#Autowired
private EntityManager entityManager;
#Autowired
private SiteRepository siteRepository;
#Override
public List<Site> getAllSites() {
Iterable<Site> sites = siteRepository.findAll();
List<Site> allSites = new ArrayList<>();
sites.forEach(allSites::add);
return allSites;
}
#Override
public List<Site> getSiteBySiteName(String siteName) {
List<Site> allSites = siteRepository.findBySiteName(siteName);
return allSites;
}
#Override
public Site updateSiteName(Long id,String siteName) {
Site site = siteRepository.findById(id).get();
if(site == null)
return null;
site.setSiteName(siteName);
siteRepository.save(site);
return site;
}
}
AOrganizationAspect.java
#Aspect
#Component
#Slf4j
public class AOrganizationAspect {
#PersistenceContext
private EntityManager entityManager;
#Pointcut("execution(public * com.harshal.springboot.springfilter.repository.AOrganizationRepository+.*(..))")
protected void aOrganizationRepositoryRepositoryMethod() {
log.info("aOrganizationRepositoryRepositoryMethod");
}
#Around(value = "aOrganizationRepositoryRepositoryMethod()")
public Object enableOwnerFilter(ProceedingJoinPoint joinPoint) throws Throwable {
// Variable holding the session
Session session = null;
try {
// Get the Session from the entityManager in current persistence context
session = entityManager.unwrap(Session.class);
// Enable the filter
Filter filter = session.enableFilter("OrgFilter");
// Set the parameter from the session
List<Long> orgList = getAllowedOrgIdList();
filter.setParameterList("allowedOrgIdList", orgList);
} catch (Exception ex) {
// Log the error
log.error("Error enabling OrgFilter : Reason -" + ex.getMessage());
}
// Proceed with the joint point
Object obj = joinPoint.proceed();
// If session was available
if (session != null) {
// Disable the filter
session.disableFilter("OrgFilter");
}
// Return
return obj;
}
private List<Long> getAllowedOrgIdList() {
return Arrays.asList(2l);
}
}
So , hibernate filters are applied if method getSiteBySiteName is called and filters are not applied if findById method is called.
Below are queries :
For getSiteBySiteName :
select site0_.id as id1_2_, site0_.org_id as org_id3_2_,
site0_.site_name as site_nam2_2_ from site site0_ where site0_.org_id
in (?) and site0_.site_name=?
Please help . Thanks in advance.
For findById
select site0_.id as id1_2_0_, site0_.org_id as org_id3_2_0_,
site0_.site_name as site_nam2_2_0_, organizati1_.id as id1_1_1_,
organizati1_.address as address2_1_1_, organizati1_.org_name as
org_name3_1_1_ from site site0_ left outer join organization
organizati1_ on site0_.org_id=organizati1_.id where site0_.id=?
findById is using the EntityManager.find method and do not create a query.
Plus Hibernate Filters only work on queries.
You should write a query instead of using findById

MappingException: Ambiguous field mapping detected

Using Spring boot 1.5.6.RELEASE.
I have the following mongo document base class:
#Document(collection="validation_commercial")
public abstract class Tier {
#Id
private String id;
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private Date created;
#Field("tran")
private Tran tran;
public Tier() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Tran getTran() {
return tran;
}
public void setTran(Tran tran) {
this.tran = tran;
}
}
which is then extended:
public class Tier1 extends Tier {
#Field("tier1")
private Tier1Programs tier1;
public Tier1() {
this.tier1 = new Tier1Programs();
}
public Tier1Programs getTier1() {
return tier1;
}
public void setTier1(Tier1Programs tier1) {
this.tier1 = tier1;
}
}
which in turn is extended:
public class Tier2 extends Tier1 {
#Field("tier2")
private Tier2Programs tier2;
public Tier2() {
this.tier2 = new Tier2Programs();
}
public Tier2Programs getTier2() {
return tier2;
}
public void setTier2(Tier2Programs tier2) {
this.tier2 = tier2;
}
}
There is a Tier1 Supervisor (Spring Boot Application) that uses the Tier1 class within the MongoRepository interface:
public interface Tier1Repository extends MongoRepository<Tier1,String>{}
for retrieving and saving - no issue.
I then have a Tier2 Supervisor (Spring Boot Application) that uses a Tier1 Repository (for retrieving the Tier1 document and a Tier2 Repository for saving the Tier2 document:
#Repository("tier1Repository")
public interface Tier1Repository extends MongoRepository<Tier1,String>{}
#Repository("tier2Repository")
public interface Tier2Repository extends MongoRepository<Tier2,String>{}
My service is:
#Service
public class TierService {
#Qualifier("tier1Repository")
#Autowired
private final Tier1Repository tier1Repository;
#Qualifier("tier2Repository")
#Autowired
private final Tier2Repository tier2Repository;
public TierService(#Qualifier("tier1Repository") Tier1Repository tier1Repository, #Qualifier("tier2Repository") Tier2Repository tier2Repository) {
this.tier1Repository = tier1Repository;
this.tier2Repository = tier2Repository;
}
public Tier1 findOne(String id) {
return tier1Repository.findOne(id);
}
public void SaveTier(Tier2 tier) {
tier2Repository.save(tier);
}
public Tier1Repository getTier1Repository() {
return tier1Repository;
}
public Tier2Repository getTier2Repository() {
return tier2Repository;
}
}
and finally the app:
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class})
#Configuration
#ComponentScan(basePackages = {"com.k12commercial.tier2supervisor"})
#ImportResource("classpath:application-context.xml")
public class Application implements CommandLineRunner {
#Autowired
private IReceiver raBidNetPriceReceiver;
#Autowired
private UdyDataSourceFactory udyDSRegistry;
public static void main(String[] args) throws InterruptedException {
try {
SpringApplication.run(Application.class, args);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run(String... args) throws Exception {
raBidNetPriceReceiver.processTierMessages();
exit(0);
}
}
When I run the Tier2 Supervisor from the command line I get the following error:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'tierService' defined in URL
[jar:file:/opt/java-commandline/tier2supervisor-1.0.jar!/BOOT-INF/classes!/com/k12commercial/tier2supervisor/service/TierService.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tier2Repository': Invocation of init method failed; nested exception is org.springframework.data.mapping.model.MappingException: Ambiguous field mapping detected! Both private final java.lang.reflect.Type org.springframework.data.util.TypeDiscoverer.type and private final java.lang.Class org.springframework.data.util.ClassTypeInformation.type map to the same field name type! Disambiguate using #Field annotation!
I am not sure if the issue is Tier2 extending Tier1 (did try putting #Document tag above Tier1 and Tier2 with no change). I think I have marked the relevant fields so don't understand the need to disambiguate. I thought the issue was having 2 repositories (Spring Boot not knowing which one to DI) so removed the Tier1Repository - didn't work. Tried better qualifying the repositories but still got the same error. I made Tier1 and Tier2 #Transient and that got rid of the message but also removed the tier1 section in the mongo document - so wrong correction.
Thinking it is an annotation fix but not seeing it...
Please advise - thank you.
Sorry for the delay (I got pulled away to work on something else) and thank you to those who responded.
The issue was I had a MongoTemplate in my Tier level programs e.g.Tier2Programs (sub library) which Spring Boot was trying to autowire.
By moving the Mongo (CRUD) requirements to the supervisor level (I also replaced the Repositories with one MongoTemplate to simplify) I removed the ambiguity. (I also removed the Service class).
The code is contained with the RaBidNetReciever class
#Component
public class RaBidNetPriceReceiver extends BaseReceiver implements IReceiver, ApplicationEventPublisherAware {
private static final Logger LOGGER = LoggerFactory.getLogger(RaBidNetPriceReceiver.class);
private final RabbitTemplate raBidNetPriceRabbitTemplate;
public RaBidNetPriceReceiver(MongoTemplate mongoTemplate, RabbitTemplate raBidNetPriceRabbitTemplate) {
super(mongoTemplate);
this.raBidNetPriceRabbitTemplate = raBidNetPriceRabbitTemplate;
}
#Transactional
public void processTierMessages() {
try {
while (true) {
gson = getGsonBuilder().create();
byte[] body = (byte[]) raBidNetPriceRabbitTemplate.receiveAndConvert();
if (body == null) {
setFinished(true);
break;
}
tier1Message = gson.fromJson(new String(body), Tier1Message.class);
// document a 'Tier1' type so retrieve Tier1 first...
Tier1 tier1 = mongoTemplate.findById(tier1Message.getId(), Tier1.class);
Tier2Message tier2Message = new Tier2Message(tier1Message.getTran(), tier1Message.getId());
Tier2Process tierProcess = getTierProcess(tier2Message.getTran().getK12ArchitectureId());
Tier2 tier2 = new Tier2();
tier2.setId(tier1.getId());
tier2.setTier1Programs(tier1.getTier1Programs());
tier2.setCreated(tier1.getCreated());
tier2.setTran(tier1.getTran());
tierProcess.setTier(tier2);
tier2 = tier2.getTier2Programs().getRaBidNetPriceProgram().process(tierProcess);
mongoTemplate.save(tier2);
if (tier2.getTier2Programs().getRaBidNetPriceProgram().isFinished()) {
// publish event
publisher.publishEvent(new ProgramEvent(this, "FINISHED", tier2Message));
}
}
} catch (Exception e) {
LOGGER.error("id: " + tier1Message.getId() + " " + e.getMessage());
}
}
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
Thank you,

camel jpa #Consumed is not being called

I'm trying to use #Consumed on jpa entity with camel.
this is my route :
<route id="incomingFileHandlerRoute">
<from
uri="jpa://com.menora.inbal.incomingFileHandler.Jpa.model.MessageToDB?consumer.nativeQuery=select
* from file_message where mstatus = 'TODO'&consumer.delay=5000&consumeDelete=false&consumeLockEntity=true&consumer.SkipLockedEntity=true" />
<to uri="bean:incomingFileHandler" />
</route>
and my entity:
#Entity
#Table(name = "file_message")
public class MessageToDB implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
private String uuid;
private String fileName;
private String body;
private String mstatus;
#Temporal(TemporalType.TIMESTAMP)
private Date mtimestamp;
#Consumed
public void updateMstatus() {
setMstatus(MessageStatus.DONE.name());
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getMstatus() {
return mstatus;
}
public void setMstatus(String mstatus) {
this.mstatus = mstatus;
}
public Date getMtimestamp() {
return mtimestamp;
}
public void setMtimestamp(Date mtimestamp) {
this.mtimestamp = mtimestamp;
}
}
I do get to incomingFileHandler bean with results from db but I do not get to the Consumed method updateMstatus . The incomingFileHandler bean is getting called continuously as always there are results from db
I have a similar implementation with camel-jpa and annotations #Consumed and #PreConsumed in the entity but none of these methods is called.
I look the camel-jpa source code and found this in JpaConsumer.java:
protected DeleteHandler<Object> createPreDeleteHandler() {
// Look for #PreConsumed to allow custom callback before the Entity has been consumed
final Class<?> entityType = getEndpoint().getEntityType();
if (entityType != null) {
// Inspect the method(s) annotated with #PreConsumed
if entityType is null the entity class inst inspect the method annotated with #Consumed and #PreConsumed.
Solution: add entityType=com.xx.yy.MessageToDB to your URI to set Endpoint Entity type.

Failed to create an instance of Service via deferred binding

I have been trying to build a GWT / Google App Engine web app using the mvp4g framework.
I keep getting an error about Failing to create an instance of my Service via deferred binding.
My Acebankroll.gwt.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='acebankroll'>
<inherits name='com.google.gwt.user.User'/>
<inherits name="com.google.gwt.i18n.I18N"/>
<inherits name='com.google.gwt.user.theme.standard.Standard'/>
<inherits name='com.mvp4g.Mvp4gModule'/>
<entry-point class='com.softamo.acebankroll.client.AceBankroll'/>
<source path='client'/>
</module>
My Entry Module looks like:
public class AceBankroll implements EntryPoint {
public void onModuleLoad() {
Mvp4gModule module = (Mvp4gModule)GWT.create( Mvp4gModule.class );
module.createAndStartModule();
RootPanel.get().add((Widget)module.getStartView());
}
}
Error Trace
I post the complete error trace as an answer.
FAQ and Trials
I have read that the next list of common mistakes may cause this error:
The ServiceAsync interfaces have methods with return values. This is wrong, all methods need to return void.
The Service interfaces don't extend the RemoteService interface.
The methods in the ServiceAsync interfaces miss the final argument of AsyncCallback.
The methods on the two interfaced, ExampleService and ExampleServiceAsync, don't match up exactly (other than the return value and AsyncCallback argument)
I have checked all the above conditions and did not find the problem.
How do you insert your services in the presenters?
Here is a snippet illustrating how I do inject the service in my presenter classes.
protected MainServiceAsync service = null;
#InjectService
public void setService( MainServiceAsync service ) {
this.service = service;
}
Do you have the required libraries?
Yes, I have commons-configuration-1.6.jar, commons-lang-2.4.jar and mvp4g-1.1.0.jar in my lib directory.
Does your project compiles?
Yes, it does compile. I use Eclipse with GWT/Google App Engine plugin. Next I post my .classpath
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" output="test-classes" path="test"/>
<classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/>
<classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/commons-configuration-1.6.jar"/>
<classpathentry kind="lib" path="lib/commons-lang-2.4.jar"/>
<classpathentry kind="lib" path="lib/mvp4g-1.1.0.jar"/>
<classpathentry kind="lib" path="test/lib/emma.jar"/>
<classpathentry kind="lib" path="test/lib/junit-4.5.jar"/>
<classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/testing/appengine-testing.jar"/>
<classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-api.jar"/>
<classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-api-labs.jar"/>
<classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-api-stubs.jar"/>
<classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-local-runtime.jar"/>
<classpathentry kind="output" path="war/WEB-INF/classes"/>
</classpath>
Are your Bean Serializable?
Yes, they are serializable. They implements the next interface:
public interface BasicBean extends Serializable {
public String getId();
public void copy(BasicBean ob);
}
They all have an empty argument constructor. Some of them have two constructors. One without arguments and one with arguments.
Some of them implement this interface
public interface NameObject extends BasicBean, BaseOwnedObject, Comparable<NameObject> {
public String getName();
public void setName(String name);
public abstract int compareTo(NameObject ob);
}
Can the Comparable cause problems?
How does your service code looks like?
I post my service code:
MainService
#RemoteServiceRelativePath( "main" )
public interface MainService extends RemoteService {
public List<UserBean> getUsers();
public void deleteUser(UserBean user);
public void createUser(UserBean user);
public void updateUser( UserBean user );
public String authenticate(String username, String password);
public boolean isSessionIdStillLegal(String sessionId);
public void signOut();
public boolean userAlreadyExists(String email);
public UserBean getByEmail(String email);
public void confirmUser(String email);
public UserBean getUserById(String id);
}
MainServiceAsync
public interface MainServiceAsync {
public void getUsers(AsyncCallback<List<UserBean>> callback);
public void deleteUser(UserBean user, AsyncCallback<Void> callback);
public void createUser(UserBean user, AsyncCallback<Void> callback);
public void updateUser( UserBean user, AsyncCallback<Void> callback);
public void authenticate(String username, String password, AsyncCallback<String> callback);
public void isSessionIdStillLegal(String sessionId, AsyncCallback<Boolean> callback);
public void signOut(AsyncCallback<Void> callback);
public void userAlreadyExists(String email, AsyncCallback<Boolean> callback);
public void getByEmail(String email, AsyncCallback<UserBean> callback );
public void confirmUser(String email, AsyncCallback<Void> callback );
public void getUserById(String id, AsyncCallback<UserBean> callback);
}
Basic Bean
import java.io.Serializable;
public interface BasicBean extends Serializable {
public String getId();
public void copy(BasicBean ob);
}
User Bean
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class UserBean implements BasicBean {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
protected Long ident;
#Persistent
private String name = null;
#Persistent
private String email = null;
#Persistent
private boolean confirmed = false;
#Persistent
private String password = null;
public UserBean() { }
public String getId() {
if( ident == null ) return null;
return ident.toString();
}
public void setId(String id) {
this.ident = Long.parseLong(id);
}
public String getEmail( ) { return email; }
public void setEmail(String email) { this. email = email; }
public String getName() { return name; }
public void setName(String name) { this. name = name; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password;}
public boolean isConfirmed() { return confirmed;}
public void setConfirmed(boolean confirmed) {this.confirmed = confirmed;}
public void copy(BasicBean ob) {
UserBean user = (UserBean) ob;
this.name = user.name;
this.email = user.email;
this.password = user.password;
}
}
Next I post an extract of web.xml
Note. I have 7 other services. I am using the module functionality of MVP4G. I have other servlets defined for each module in web.xml
<servlet>
<servlet-name>mainServlet</servlet-name>
<servlet-class>com.softamo.acebankroll.server.MainServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mainServlet</servlet-name>
<url-pattern>/acebankroll/main</url-pattern>
</servlet-mapping>
Server
BaseServiceImpl
public abstract class BaseServiceImpl extends RemoteServiceServlet {
protected Map users = new HashMap();
protected static final MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
protected static final Logger log = Logger.getLogger(BaseServiceImpl.class.getName());
protected String getSessionId() {
return getThreadLocalRequest().getSession().getId();
}
protected String getCurrentUserId() {
String id = getSessionId();
UserBean user = (UserBean) users.get(id);
if(user!=null)
return user.getId();
return null;
}
protected void saveBaseObject(BasicBean ob) {
PersistenceManager pm = JdoUtil.getPm();
String sessionId = getSessionId();
UserBean user = (UserBean) users.get(sessionId);
if(user!=null) {
String user_id = user.getId();
((BaseOwnedObject)ob).setUserId(user_id);
pm.makePersistent(ob);
}
}
protected void deleteBaseObject(Class classname, String id) {
PersistenceManager pm = JdoUtil.getPm();
pm.deletePersistent( pm.getObjectById(classname, Long.parseLong(id) ));
}
protected List getAll(Class class_name) {
PersistenceManager pm = JdoUtil.getPm();
pm.setDetachAllOnCommit(true);
Query q = pm.newQuery(class_name);
if(q==null)
return new ArrayList<BasicBean>();
q.setFilter("userId == userIdParam");
q.declareParameters("String userIdParam");
String userId = getCurrentUserId();
return (List) q.execute(userId);
}
public boolean isSessionIdStillLegal(String sessionId) {
return (users.containsKey(sessionId))? true : false;
}
public void signOut() {
String id = getSessionId();
synchronized(this) {
users.remove(id);
}
}
public BasicBean getObjectById(Class classname, String id) {
BasicBean result = null;
PersistenceManager pm = JdoUtil.getPm();
pm.setDetachAllOnCommit(true);
result = pm.getObjectById(classname, Long.parseLong(id) );
return result;
}
}
MainServiceImpl
public class MainServiceImpl extends BaseServiceImpl implements MainService {
public MainServiceImpl() {}
public String authenticate(String username, String password) {
PersistenceManager pm = JdoUtil.getPm();
UserBean user = getByEmail(username);
if(user==null || !user.isConfirmed())
return null;
String hashFromDB = user.getPassword();
boolean valid = BCrypt.checkpw(password, hashFromDB);
if(valid) {
String id = getSessionId();
synchronized( this ) {
users.put(id, user) ;
}
return id;
}
return null;
}
public void deleteUser(UserBean user) {
deleteBaseObject(UserBean.class, user.getId());
}
public List<UserBean> getUsers() {
PersistenceManager pm = JdoUtil.getPm();
pm.setDetachAllOnCommit(true);
Query q = pm.newQuery(UserBean.class);
if(q==null)
return new ArrayList<UserBean>();
return (List) q.execute();
}
public boolean userAlreadyExists(String email) {
return (getByEmail(email)!=null) ? true : false;
}
public void updateUser(UserBean object) {
saveBaseObject(object);
}
public void confirmUser(String email) {
PersistenceManager pm = JdoUtil.getPm();
UserBean user = getByEmail(email);
if(user!=null) {
user.setConfirmed(true);
pm.makePersistent(user);
}
}
public void createUser(UserBean user) {
PersistenceManager pm = JdoUtil.getPm();
String sessionId = getSessionId();
// Only store it if it does not exists
if( (getByEmail(user.getEmail()))==null) {
String hash = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt());
user.setPassword(hash);
pm.makePersistent(user);
synchronized( this ) {
users.put(sessionId, user);
}
}
}
public UserBean getByEmail(String email) {
return new MyAccountServiceImpl().getByEmail(email);
}
public UserBean getUserById(String id) {
return new MyAccountServiceImpl().getUserById(id);
}
}
SOLUTION
Apparently the Google App Engine Annotations in my Bean classes were causing the problem. Removing the annotation from the client side code solved the issue. What I do know if I have the classes with the JDO notation in the server side. That it is to say the beans are plain data transfere object which get cloned into object with JDO annotations in the server side.
I am literally stacked. I do not know what to try. Any help is really appreciated!
If your service methods contains POJO's they can cause you problems, they must have a zero argument constructor or no constructor defined. Also they must implement either IsSerializable or Serializable.
You can trie to create the service manually with:
MainServiceAsync service = GWT.create(MainService.class);
And maybe post the MainService classes.
Edited:
This is an output from the treelogger with a deferred binding failing, and it is outputed into the console when you do a gwt compile. You can also see this output in the devmode console if you run in hosted mode. Always check the first error, because the others are most of the time caused by the first error.
Compiling module se.pathed.defa.DefaultGwtProject
Scanning for additional dependencies: file:/C:/Users/Patrik/workspace/skola-workspace/DefaultGwtProject/src/se/pathed/defa/client/DefaultGwtProject.java
Computing all possible rebind results for 'se.pathed.defa.client.GreetingService'
Rebinding se.pathed.defa.client.GreetingService
Invoking com.google.gwt.dev.javac.StandardGeneratorContext#16c6a55
Generating client proxy for remote service interface 'se.pathed.defa.client.GreetingService'
[ERROR] se.pathed.defa.shared.UserBean is not default instantiable (it must have a zero-argument constructor or no constructors at all) and has no custom serializer. (reached via se.pathed.defa.shared.UserBean)
[ERROR] se.pathed.defa.shared.UserBean has no available instantiable subtypes. (reached via se.pathed.defa.shared.UserBean)
[ERROR] subtype se.pathed.defa.shared.UserBean is not default instantiable (it must have a zero-argument constructor or no constructors at all) and has no custom serializer. (reached via se.pathed.defa.shared.UserBean)
[ERROR] Errors in 'file:/C:/Users/Patrik/workspace/skola-workspace/DefaultGwtProject/src/se/pathed/defa/client/DefaultGwtProject.java'
[ERROR] Line 37: Failed to resolve 'se.pathed.defa.client.GreetingService' via deferred binding
Scanning for additional dependencies: jar:file:/C:/eclipse/plugins/com.google.gwt.eclipse.sdkbundle.2.0.3_2.0.3.v201002191036/gwt-2.0.3/gwt-user.jar!/com/google/gwt/core/client/impl/SchedulerImpl.java
[WARN] The following resources will not be created because they were never committed (did you forget to call commit()?)
[WARN] C:\Users\Patrik\AppData\Local\Temp\gwtc301646733929273376.tmp\se.pathed.defa.DefaultGwtProject\compiler\se.pathed.defa.client.GreetingService.rpc.log
[WARN] For the following type(s), generated source was never committed (did you forget to call commit()?)
[WARN] se.pathed.defa.client.GreetingService_Proxy
[ERROR] Cannot proceed due to previous errors
This can happen if anything that is in your client package has an import that is not whitelisted. For example i hit this because my autoimport imported an apache commons lang class into my client code.
One would have to look at their imports to make sure nothing odd is in the client code.
GWT projects are structured like:
com.app.client
com.app.server
you can't having anything that not GWT compatible in client.

Resources