MappingException: Ambiguous field mapping detected - spring-data-mongodb

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,

Related

Apache Camel Generic Router - pass exchange properties to static class methods

I am trying to create a generic router whose processor and other attributes are populated from a static class. Here is sample code.
public class GenericRouter extends RouteBuilder( {
#Override
public void configure() throws Exception {
from("direct:generic-route")
.process(Util.getProcesss(“${exchangeProperty[processKey]"))
.ToD(Util.getUrl(“${exchangeProperty[urlKey]"));
}
}
Public class Util{
Map<String,Object> routerResources;
static {
//load routerResources
}
public static Processor getProcessor(String processorKey){
return (Processor)routerResources.get(processorKey);
}
public static Processor getUrl(String urlKey){
return (String)routerResources.get(urlKey);
}
}
The generic router is expected to post a rest call. the properties "urlKey" and "processorUrl" are already available in exchange. I finding it difficult to pass exchange properties to static Util class methods.
If you want to access properties of an exchange in plain java you can use .process or .exchange. If you need to access body or headers you can use e.getMessage().getBody() and e.getMessage().getHeader()
from("direct:generic-route")
.process( e -> {
String processKey = e.getProperty("processKey", String.class);
Processor processor = Util.getProcessor(processKey);
processor.process(e);
})
.setProperty("targetURL").exchange( e -> {
String urlKey = e.getProperty("urlKey", String.class);
return Util.getUrl(urlKey);
})
.toD("${exchangeProperty.targetURL}");
Also make sure you fix the return type of this method:
public static Processor getUrl(String urlKey){
return (String)routerResources.get(urlKey);
}
As a side note, you can actually use map stored in body, header or property through simple language.
public class ExampleTest extends CamelTestSupport {
#Test
public void example(){
template.sendBodyAndHeader("direct:example", null, "urlKey", "urlA");
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
Map<String, String> urlMap = new HashMap<>();
urlMap.put("urlA", "direct:pointA");
urlMap.put("urlB", "direct:pointB");
from("direct:example")
.setProperty("urlMap").constant(urlMap)
.log("url: ${exchangeProperty.urlMap['${headers.urlKey}']}");
}
};
}
}

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

Spring-boot & multiple database connections: autowire service does not work

I'm writing an Spring-boot application that needs to connect to at least 2 databases.
I have 1 project per database in order to define their domains, 1 project per database in order to define their services and 1 Vaadin project for the UI.
- a business domain entity sample
#Entity
#Table(name="T_PARAMETER")
public class Parameter extends BaseIdEntity implements Serializable {
#Column(name="par_cls")
#NotNull
private String parameterClass;
#Column(name="par_cd")
#NotNull
private String parameterCode;
#Column(name="par_lan")
#NotNull
private String language;
#Column(name="par_sht_val")
#NotNull
private String parameterValueShort;
#Column(name="par_lng_val")
#NotNull
private String parameterValueLong;
- a authentication domain entity sample
#Entity
#Table(name="t_user", schema="authenticate")
public class User extends BaseIdEntity implements Serializable {
#Id
#Column(name="user_cd")
private String userCode;
#Column(name="pwd")
#NotNull
private String password;
#Column(name="new_pwd_req")
#NotNull
private boolean passwordRequired;
#Column(name="acc_lck")
#NotNull
private boolean accountLocked;
There are repositories onto these 2 entities beans, they just extends the JpaRepository as hereunder:
public interface ParameterRepository extends JpaRepository<Parameter,Integer>{}
the services are defined as hereunder:
#Service
#Transactional(transactionManager="authenticateTransactionManager")
public class ServiceParameterImpl implements ServiceParameter {
private final static Logger log = LoggerFactory.getLogger(ServiceParameterImpl.class);
#Autowired
private ParameterRepository parameterRepository;
#Override
#Transactional(readOnly=true,transactionManager="authenticateTransactionManager")
public List<Parameter> findParameterHeader(String filter) {
.../...
The client application as:
#SpringBootApplication
#Configuration
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class
, HibernateJpaAutoConfiguration.class
, DataSourceTransactionManagerAutoConfiguration.class })
#ComponentScan(
basePackages= {
"org.associative.ui"
,"org.associative.service"
})
#Import({AssociativityConfiguration.class, AuthenticateConfiguration.class})
public class Application {
private final static Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and configurations:
#Configuration
#EnableTransactionManagement
#EntityScan(basePackages= "org.associative.domain.associativity")
#EnableJpaRepositories(
basePackages = "org.associative.domain.associativity.repository"
, entityManagerFactoryRef = "associativityEntityManager"
, transactionManagerRef = "associativityTransactionManager"
)
#ConfigurationProperties(prefix = "db.associativity")
public class AssociativityConfiguration {
private final static Logger log = LoggerFactory.getLogger(AssociativityConfiguration.class);
#Autowired
private Environment env;
private final static String ASSOCIATIVITY_DRIVER_CLASS_NAME = "db.associativity.classname";
private final static String ASSOCIATIVITY_URL = "db.associativity.connectionUrl";
private final static String ASSOCIATIVITY_USERNAME = "db.associativity.username";
private final static String ASSOCIATIVITY_PASSWORD = "db.associativity.password";
private final static String HIBERNATE_DIALECT = "hibernate.dialect";
#Bean(name = "associativityDataSource")
public DataSource datasource() {
DataSource dataSource = DataSourceBuilder.create()
.driverClassName(env.getProperty(ASSOCIATIVITY_DRIVER_CLASS_NAME))
.url(env.getProperty(ASSOCIATIVITY_URL))
.username(env.getProperty(ASSOCIATIVITY_USERNAME))
.password(env.getProperty(ASSOCIATIVITY_PASSWORD)).build();
if (log.isTraceEnabled())
log.trace(String.format("associativityConfiguration datasource:%s", dataSource.toString()));
return dataSource;
}
#Bean(name = "associativityEntityManager")
#PersistenceContext(unitName = "associativity")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("associativityDataSource") DataSource dataSource) {
Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put(HIBERNATE_DIALECT, env.getProperty(HIBERNATE_DIALECT));
LocalContainerEntityManagerFactoryBean em = builder.dataSource(dataSource)
.packages("org.associative.domain.authenticate").persistenceUnit("pu_associativity").properties(jpaProperties)
.build();
em.setJpaPropertyMap(jpaProperties);
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(adapter); // not mandatory definition
return em;
}
#Bean(name = "associativityTransactionManager")
public PlatformTransactionManager associativityTransactionManager(
#Qualifier("associativityEntityManager") EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
and
#Configuration
#EnableTransactionManagement
#EntityScan(basePackages= "org.associative.domain.authenticate")
#EnableJpaRepositories(
basePackages = "org.associative.domain.authenticate.repository"
, entityManagerFactoryRef = "authenticateEntityManager"
, transactionManagerRef = "authenticateTransactionManager"
)
#ConfigurationProperties(prefix="db.authenticate")
public class AuthenticateConfiguration {
private final static Logger log = LoggerFactory.getLogger(AuthenticateConfiguration.class);
#Autowired
private Environment env;
private final static String AUTHENTICATE_DRIVER_CLASS_NAME= "db.authenticate.classname";
private final static String AUTHENTICATE_URL = "db.authenticate.connectionUrl";
private final static String AUTHENTICATE_USERNAME = "db.authenticate.username";
private final static String AUTHENTICATE_PASSWORD = "db.authenticate.password";
private final static String HIBERNATE_DIALECT = "hibernate.dialect";
#Primary
#Bean(name = "authenticateDataSource")
public DataSource datasource() {
DataSource dataSource = DataSourceBuilder.create()
.driverClassName(env.getProperty(AUTHENTICATE_DRIVER_CLASS_NAME))
.url(env.getProperty(AUTHENTICATE_URL))
.username(env.getProperty(AUTHENTICATE_USERNAME))
.password(env.getProperty(AUTHENTICATE_PASSWORD))
.build();
if ( log.isTraceEnabled()) log.trace(String.format("authenticateDataSource datasource:%s", dataSource.toString()));
return dataSource;
}
#Primary
#Bean(name="authenticateEntityManager")
#PersistenceContext(unitName = "authenticate")
//https://raymondhlee.wordpress.com/tag/enablejparepositories/
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("authenticateDataSource")DataSource dataSource) {
Map<String,Object> jpaProperties = new HashMap<>();
jpaProperties.put(HIBERNATE_DIALECT, env.getProperty(HIBERNATE_DIALECT));
LocalContainerEntityManagerFactoryBean em = builder
.dataSource(dataSource)
.packages("org.associative.domain.authenticate")
.persistenceUnit("pu_authenticate")
.properties(jpaProperties)
.build();
em.setJpaPropertyMap(jpaProperties);
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(adapter); // not mandatory definition
return em;
}
#Primary
#Bean(name="authenticateTransactionManager")
public PlatformTransactionManager authenticateTransactionManager(
#Qualifier("authenticateEntityManager")EntityManagerFactory entityManagerFactory){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
I'm facing an issue when a service is built by using autowiring in the construction of my client interface:
#SpringUI
public class ParameterListView extends CssLayout implements Serializable {
private final static Logger log = LoggerFactory.getLogger(ParameterListView.class);
#Autowired
private ParameterController controller;
#PostConstruct
private void initView() {
if ( log.isTraceEnabled() ) log.trace(String.format("initView:%s", "no param"));
Grid<Parameter> grid = new Grid<>();
this.addComponent(grid);
grid.setItems(controller.getParameterHeader(""));
grid.addColumn(Parameter::getParameterClass);
grid.addColumn(Parameter::getParameterValueShort);
grid.addColumn(Parameter::getParameterValueLong);
2017-12-01 14:20:07.151 ERROR o.s.b.SpringApplication Application startup failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'parameterControllerImpl': Unsatisfied
dependency expressed through field 'serviceParameter'; nested
exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'serviceParameterImpl': Unsatisfied
dependency expressed through field 'parameterRepository'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'parameterRepository': Invocation of
init method failed; nested exception is
java.lang.IllegalArgumentException: Not a managed type: class
org.associative.domain.associativity.Parameter
I already spent a lot of time in order to solve the multiple database connections because I was thinking this issue comes from a definition problem but I'm not sure now.
So, what should I look to in order to solve this.
Thank you very much.
The last line of your stack trace is a clue: Not a managed type: class org.associative.domain.associativity.Parameter. Hibernate doesn't know about your Parameter entity.
In the LocalContainerEntityManagerFactoryBean you set packages to scan to org.associative.domain.authenticate. Your Parameter entity is not under this package.
This should fix the problem:
.packages("org.associative.domain.authenticate", "org.associative.domain.associativity")

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

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.

Bidirectional communication from Camel to Vertx socket Server

I am trying to use Camel NettyComponent to communicate with a SocketServer written in Vert.x.
This is my server code:
public class NettyExampleServer {
public final Vertx vertx;
public static final Logger logger = LoggerFactory.getLogger(NettyExampleServer.class);
public static int LISTENING_PORT = 15692;
public NettyExampleServer(Vertx vertx) {
this.vertx = vertx;
}
private NetServer netServer;
private List<String> remoteAddresses = new CopyOnWriteArrayList<String>();
private final AtomicInteger disconnections = new AtomicInteger();
public int getDisconnections(){
return disconnections.get();
}
public List<String> getRemoteAddresses(){
return Collections.unmodifiableList(remoteAddresses);
}
public void run(){
netServer = vertx.createNetServer();
netServer.connectHandler(new Handler<NetSocket>() {
#Override
public void handle(final NetSocket socket) {
remoteAddresses.add(socket.remoteAddress().toString());
socket.closeHandler(new Handler<Void>() {
#Override
public void handle(Void event) {
disconnections.incrementAndGet();
}
});
socket.dataHandler(new Handler<Buffer>() {
#Override
public void handle(Buffer event) {
logger.info("I received {}",event);
socket.write("I am answering");
}
});
}
});
netServer.listen(LISTENING_PORT);
}
public void stop(){
netServer.close();
}
}
I tried to build a Route like the following:
public class NettyRouteBuilder extends RouteBuilder {
public static final String PRODUCER_BUS_NAME = "producerBus";
public static final String CONSUMER_BUS_NAME = "receiverBus";
private Processor processor = new Processor(){
#Override
public void process(Exchange exchange) throws Exception {
exchange.setPattern(ExchangePattern.InOut);
}
};
#Override
public void configure() throws Exception {
from("vertx:" + PRODUCER_BUS_NAME).process(processor).to("netty:tcp://localhost:"+ NettyExampleServer.LISTENING_PORT + "?textline=true&lazyChannelCreation=true&option.child.keepAlive=true").to("vertx:"+CONSUMER_BUS_NAME);
}
}
My tests shows that:
If I eliminate the processor on the route, the delivery succeed but there is no answer by the server
If I keep the processor, the data is delivered to the server but an exception raise because no data is received.
I have created a small project here: https://github.com/edmondo1984/netty-camel-vertx . How do I use Camel Netty Component to create a bidirectional route ?
To communicate Vertx and Camel the best tool is to use one of this:
Camel Vertex endpoint
Vertex Camel connector
You can find an example here
If you could or have another requeriments it is possible also to use a common connector like Netty on the both sides.

Resources