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

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")

Related

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

How can i set language from SQLServerDataSource using Spring data

Good I have the need to make certain queries to the database sql server working with dates, I am presented with the inconvenience that as language in the installation of sql server is in English therefore the results are defined in that language for example to perform the consult with the following function DATENAME (WEEKDAY, date) the result would be for example Tuesday, as far as my need is to show it in Spanish.
A solution that I have applied is to do this from the application, obtaining the date and perform the conversion from the application.
But I would like to know if it is possible to make this configuration globally from the application through the configuration parameters of the DataSource?
Configuration:
#Configuration
#EnableJpaRepositories(basePackages = { "com.company.app.repository" })
#ComponentScan(basePackages = { "com.company.app.repository" })
#EnableTransactionManagement
#EnableJpaAuditing
#PropertySource("classpath:/db.properties")
public class ApplicationConfig {
#Autowired
private Environment environment;
//private static final Logger LOGGER = LogManager.getLogger(ApplicationConfig.class);
#Bean
public DataSource dataSource() {
// OracleDataSource oracleDS = null;
SQLServerDataSource dataSource = null;
// oracleDS = new OracleDataSource();
dataSource = new SQLServerDataSource();
dataSource.setURL(environment.getProperty("cendb.url"));//
dataSource.setUser(environment.getProperty("cendb.user"));//
dataSource.setPassword(environment.getProperty("cendb.password"));
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
vendorAdapter.setShowSql(true);
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.SQLServerDialect");
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.company.app.model");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
#Bean
public AuditorAware<String> createAuditorProvider() {
return new CustomAuditorAware();
}
#Bean
public AuditingEntityListener createAuditingListener() {
return new AuditingEntityListener();
}

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,

Does Flink SQL support Java Map types?

I'm trying to access a key from a map using Flink's SQL API. It fails with the error Exception in thread "main" org.apache.flink.table.api.TableException: Type is not supported: ANY
Please advise how i can fix it.
Here is my event class
public class EventHolder {
private Map<String,String> event;
public Map<String, String> getEvent() {
return event;
}
public void setEvent(Map<String, String> event) {
this.event = event;
}
}
Here is the main class which submits the flink job
public class MapTableSource {
public static void main(String[] args) throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<EventHolder> mapEventStream = env.fromCollection(getMaps());
// register a table and use SQL
StreamTableEnvironment tableEnv = TableEnvironment.getTableEnvironment(env);
tableEnv.registerDataStream("mapEvent", mapEventStream);
//tableEnv.registerFunction("orderSizeType", new OrderSizeType());
Table alerts = tableEnv.sql(
"select event['key'] from mapEvent ");
DataStream<String> alertStream = tableEnv.toAppendStream(alerts, String.class);
alertStream.filter(new FilterFunction<String>() {
private static final long serialVersionUID = -2438621539037257735L;
#Override
public boolean filter(String value) throws Exception {
System.out.println("Key value is:"+value);
return value!=null;
}
});
env.execute("map-tablsource-job");
}
private static List<EventHolder> getMaps(){
List<EventHolder> list = new ArrayList<>();
for(int i=0;i<5;i++){
EventHolder holder = new EventHolder();
Map<String,String> map = new HashMap<>();
map.put("key", "value");
holder.setEvent(map);
list.add(holder);
}
return list;
}
}
When I run it I'm getting the exception
Exception in thread "main" org.apache.flink.table.api.TableException: Type is not supported: ANY
at org.apache.flink.table.api.TableException$.apply(exceptions.scala:53)
at org.apache.flink.table.calcite.FlinkTypeFactory$.toTypeInfo(FlinkTypeFactory.scala:341)
at org.apache.flink.table.plan.logical.LogicalRelNode$$anonfun$12.apply(operators.scala:530)
at org.apache.flink.table.plan.logical.LogicalRelNode$$anonfun$12.apply(operators.scala:529)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.Iterator$class.foreach(Iterator.scala:742)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1194)
at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
at scala.collection.AbstractIterable.foreach(Iterable.scala:54)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.apache.flink.table.plan.logical.LogicalRelNode.<init>(operators.scala:529)
at org.apache.flink.table.api.TableEnvironment.sql(TableEnvironment.scala:503)
at com.c.p.flink.MapTableSource.main(MapTableSource.java:25)
I'm using flink 1.3.1
I think the problem lies in fromCollection. Flink is not able to extract the needed type information because of Java limitations (i.e. type erasure). Therefore you map is treated as black box with SQL ANY type. You can verify the types of your table by using tableEnv.scan("mapEvent").printSchema(). You can specify the type information in fromCollection with Types.MAP(Types.STRING, Types.STRING).
I solved a similar issue with the following:
//Should probably make MapVal more generic, but works for this example
public class MapVal extends ScalarFunction {
public String eval(Map<String, String> obj, String key) {
return obj.get(key);
}
}
public class Car {
private String make;
private String model;
private int year;
private Map<String, String> attributes;
//getters/setters...
}
//After registering Stream and TableEnv etc
tableEnv.registerFunction("mapval", new MapVal());
Table cars = tableEnv
.scan("Cars")
.select("make, model, year, attributes.mapval('name')");

Spring data JPA save causes error on child entities

I am new to Spring Data JPA and CRUD repositories. I have code that can save to the database if I save each individual entity, but thought that I should be able to save the parent entity and have the contained child entities automatically get saved or updated. Am I doing something wrong?
The code that executes the save:
private static CustomerRepository customerRepository;
#Transactional
public ResultCreateCustomer addCustomer(NameTable nameIn, Address addressIn)
throws Exception {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
customerRepository = context.getBean(CustomerRepository.class);
ResultCreateCustomer result = new ResultCreateCustomer(0, 0, 0, DATABASE_OR_SYSTEM_ERROR);
try {
NameTable theName = new NameTable();
theName.setFirstName(nameIn.getFirstName());
theName.setLastName(nameIn.getLastName());
Address theAddress = new Address();
theAddress.setStreetNo(addressIn.getStreetNo());
theAddress.setStreetName(addressIn.getStreetName());
theAddress.setCityStateZip(addressIn.getCityStateZip());
Customer theCustomer = new Customer();
theCustomer.setNameTable(theName);
theCustomer.setAddress(theAddress);
customerRepository.save(theCustomer);
} catch (Exception e) {
this.log.error("got exception: " + e.getClass() + ": " + e.getMessage());
}
context.close();
return result;
}
The code for the Customer entity:
#Entity
#org.hibernate.annotations.Proxy(lazy=false)
#Table(name="Customer")
public class Customer implements Serializable {
public Customer() {
}
#Column(name="ID", nullable=false, unique=true)
#Id
#GeneratedValue(generator="COM_COMPORIUM_CUSTOMER_DOMAIN_CUSTOMER_ID_GENERATOR")
#org.hibernate.annotations.GenericGenerator(name="COM_COMPORIUM_CUSTOMER_DOMAIN_CUSTOMER_ID_GENERATOR", strategy="native")
private int ID;
#ManyToOne(targetEntity=com.comporium.customer.addresses.Address.class, fetch=FetchType.LAZY)
#org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.LOCK})
#JoinColumns({ #JoinColumn(name="AddressID", referencedColumnName="ID") })
private com.comporium.customer.addresses.Address address;
#OneToOne(targetEntity=com.comporium.customer.contactrolodex.NameTable.class, fetch=FetchType.LAZY)
#org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK})
#JoinColumns({ #JoinColumn(name="NameTableID", nullable=false) })
private com.comporium.customer.contactrolodex.NameTable nameTable;
#Column(name="IndustryCode", nullable=false)
private int industryCode;
#Column(name="DemographicCode", nullable=false)
private int demographicCode;
#Column(name="Ranking", nullable=false)
private int ranking;
public void setNameTable(com.comporium.customer.contactrolodex.NameTable value) {
this.nameTable = value;
}
public com.comporium.customer.contactrolodex.NameTable getNameTable() {
return nameTable;
}
// Other setters and getters follow
}
The code for the first child class:
#Entity
#org.hibernate.annotations.Proxy(lazy=false)
#Table(name="NameTable")
public class NameTable implements Serializable {
public NameTable() {
}
#Column(name="ID", nullable=false, unique=true)
#Id
#GeneratedValue(generator="COM_COMPORIUM_CUSTOMER_CONTACTROLODEX_NAMETABLE_ID_GENERATOR")
#org.hibernate.annotations.GenericGenerator(name="COM_COMPORIUM_CUSTOMER_CONTACTROLODEX_NAMETABLE_ID_GENERATOR", strategy="native")
private int ID;
#Column(name="FirstName", nullable=true, length=30)
private String firstName;
#Column(name="LastName", nullable=true, length=40)
private String lastName;
#OneToOne(mappedBy="nameTable", targetEntity=com.comporium.customer.domain.Customer.class, fetch=FetchType.LAZY)
#org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK})
private com.comporium.customer.domain.Customer customer;
}
The repository interface, CustomerRepository:
package com.comporium.customer.repositories;
import org.springframework.data.repository.CrudRepository;
import com.comporium.customer.domain.Customer;
public interface CustomerRepository extends CrudRepository<Customer, Integer> {
}
When I run the executable (via a SOAP call), I get an exception:
2014-11-19 09:57:59,253 ERROR VPcodeDao:306 - got exception: class org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.comporium.customer.domain.Customer.nameTable -> com.comporium.customer.contactrolodex.NameTable; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.comporium.customer.domain.Customer.nameTable -> com.comporium.customer.contactrolodex.NameTable
Is there a way for the save(theCustomer) to save the contained child entities also?
not sure if you ever get a solution for this. but the solution is to define cascading
#OneToOne(cascade = {CascadeType.ALL}, mappedBy="nameTable", targetEntity=com.comporium.customer.domain.Customer.class, fetch=FetchType.LAZY)

Resources