i am using Spring-Batch with the MongoDbWriter.
So we use Spring-Data-MongoDB and when the ItemWriter is called a Class-Cast-Exception is thrown:
10:40:13.795 [jobLauncherTaskExecutor-1] DEBUG o.s.b.c.r.dao.JdbcJobExecutionDao - Truncating long message before update of JobExecution: JobExecution: id=0, version=1, startTime=Wed Jun 17 10:40:01 CEST 2015, endTime=Wed Jun 17 10:40:13 CEST 2015, lastUpdated=Wed Jun 17 10:40:13 CEST 2015, status=FAILED, exitStatus=exitCode=FAILED;exitDescription=java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be cast to com.mongodb.BasicDBList
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:384)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:353)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:78)
at org.springframework.data.mongodb.core.MongoTemplate.toDbObject(MongoTemplate.java:809)
at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:962)
at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:911)
at org.springframework.batch.item.data.MongoItemWriter.doWrite(MongoItemWriter.java:128)
at org.springframework.batch.item.data.MongoItemWriter$1.beforeCommit(MongoItemWriter.java:156)
at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:95)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:928)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:740)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:150)
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:77)
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:368)
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:198)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:386)
at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:135)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:304)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
, job=[JobInstance: id=0, version=0, Job=[NBO.READER.]], jobParameters=[{}]
We use spring-data-mongodb-1.7.0.RELEASE, but i think there is a bug:
the "doSave" method in MongoTemplate calls toDbObject and this method returns allways a BasicDBObject except it is a String. So when i save a List this method returns a BasicDBObject...
private <T> DBObject toDbObject(T objectToSave, MongoWriter<T> writer) {
if (!(objectToSave instanceof String)) {
DBObject dbDoc = new BasicDBObject();
writer.write(objectToSave, dbDoc);
return dbDoc;
} else {
try {
return (DBObject) JSON.parse((String) objectToSave);
} catch (JSONParseException e) {
throw new MappingException("Could not parse given String to save into a JSON document!", e);
}
}
}
After this, the write()-Method of MappingMongoConverter is called and throws the exception, because:
if (!handledByCustomConverter && !(dbo instanceof BasicDBList)) {
typeMapper.writeType(type, dbo);
}
but it is not a BasicDBList, because of the toDbObject-Method.
Then the writeInternal-Method is called and there:
if (Collection.class.isAssignableFrom(entityType)) {
writeCollectionInternal((Collection<?>) obj, ClassTypeInformation.LIST, (BasicDBList) dbo);
return;
}
This makes boom^^
It seems that the toDbObject-Method is wrong? Is that a bug?
Greetings
A workaround is to override the MongoTemplate-Class:
public class MongoHack extends MongoTemplate
{
public MongoHack(MongoDbFactory mongoDbFactory)
{
super(mongoDbFactory);
// TODO Auto-generated constructor stub
}
#Override
protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer)
{
this.assertUpdateableIdIfNotSet(objectToSave);
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
DBObject dbDoc = this.toDbObject(objectToSave, writer);
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc));
Object id = saveDBObject(collectionName, dbDoc, objectToSave.getClass());
populateIdIfNecessary(objectToSave, id);
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc));
}
private void assertUpdateableIdIfNotSet(Object entity)
{
MongoPersistentEntity<?> persistentEntity = super.getConverter().getMappingContext()
.getPersistentEntity(entity.getClass());
MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
if (idProperty == null || persistentEntity == null) {
return;
}
Object idValue = persistentEntity.getPropertyAccessor(entity).getProperty(idProperty);
if (idValue == null && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.getType())) {
throw new InvalidDataAccessApiUsageException(String.format(
"Cannot autogenerate id of type %s for entity of type %s!", idProperty.getType().getName(), entity
.getClass().getName()));
}
}
private <T> DBObject toDbObject(T objectToSave, MongoWriter<T> writer)
{
if (Collection.class.isAssignableFrom(objectToSave.getClass())) {
DBObject dbDoc = new BasicDBObject();
Collection<T> objects = (Collection<T>) objectToSave;
Iterator<T> iterator = objects.iterator();
while(iterator.hasNext()) {
writer.write(iterator.next(), dbDoc);
}
return dbDoc;
}
else if (!(objectToSave instanceof String)) {
DBObject dbDoc = new BasicDBObject();
writer.write(objectToSave, dbDoc);
return dbDoc;
}
else {
try {
return (DBObject) JSON.parse((String) objectToSave);
}
catch (JSONParseException e) {
throw new MappingException("Could not parse given String to save into a JSON document!", e);
}
}
}
}
That works for me ... But i don not know if that is a helpfull usecase?
Related
I have jdbs template for sql for sql statements, and use hikari connection pool, after after several calls
i took exception, i used try-with-resources, where is my mistake?(Servlet Container -Tomcat)
public class SimpleJdbcTemplate {
private Connection connection;
private DataSource dataSource;
private ResultSet resultSet;
PreparedStatement preparedStatement;
public SimpleJdbcTemplate(Connection connection) {
this.connection = connection;
}
//private DataSourse datasource - из hikariconnectionpool
public SimpleJdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) {
try (PreparedStatement preparedStatement = dataSource.getConnection().prepareStatement(sql)){
resultSet = null;
List<T> result = new ArrayList<>();
int position = 1;
for (Object arg : args) {
preparedStatement.setObject(position, arg);
position++;
}
if (sql.contains("UPDATE") || sql.contains("update") ||sql.toLowerCase().contains("delete")||sql.toLowerCase().contains("insert")) {
preparedStatement.executeUpdate();
} else{
resultSet = preparedStatement.executeQuery();
if (resultSet == null) {
throw new SQLException("No resultsSet");
}
while (resultSet.next()) {
result.add(rowMapper.mapRow(resultSet));
}
}
log.info(result.toString());
return result;
} catch (SQLException e) {
throw new IllegalStateException(e);
Logs:
24-Oct-2020 13:46:16.633 SEVERE [http-nio-8080-exec-3] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [servlets.view.MessendjerViewServlet] in context with path [/LabWork_war] threw exception
java.lang.IllegalStateException: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30014ms.
at repository.utill.SimpleJdbcTemplate.query(SimpleJdbcTemplate.java:52)
at repository.jdbc.UserRepositoryImpl.findUserByUUID(UserRepositoryImpl.java:84)
at service.UserService.findUser(UserService.java:71)
at servlets.filter.AuthFilter.doFilter(AuthFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30014ms.
at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:695)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:197)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:162)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:100)
at repository.utill.SimpleJdbcTemplate.query(SimpleJdbcTemplate.java:27)
... 22 more
Okey i founded mistake this line is dont work correctly(try-with-resources)
(reparedStatement preparedStatement = dataSource.getConnection().prepareStatement(sql))
i think when i try to close connection it tooks a random connection from datasource(dataSource.getConnection()),so,my connection was always open, i reformated code to this
public class SimpleJdbcTemplate {
DataSource dataSource;
//private DataSourse datasource - из hikariconnectionpool
public SimpleJdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) { //TODO repair connection leak
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(sql);
resultSet = null;
List<T> result = new ArrayList<>();
int position = 1;
for (Object arg : args) {
preparedStatement.setObject(position, arg);
position++;
}
if (sql.contains("UPDATE") || sql.contains("update") || sql.toLowerCase().contains("delete") || sql.toLowerCase().contains("insert")) {
preparedStatement.executeUpdate();
} else {
resultSet = preparedStatement.executeQuery();
if (resultSet == null) {
throw new SQLException("No resultsSet");
}
while (resultSet.next()) {
result.add(rowMapper.mapRow(resultSet));
}
}
log.info(result.toString());
return result;
} catch (SQLException e) {
throw new IllegalStateException(e);
} finally {
try {
if (resultSet != null) {
resultSet.close();
log.info("resultes finaly closed? - {}", resultSet.isClosed());
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
if (preparedStatement != null) {
try {
preparedStatement.close();
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
try {
if (connection != null) {
connection.close();
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
all worked as it should
I have code snippet below.
What I want is if getNames() method catch an exception
( ex. InterruptedException ),
want to check if Got InterruptedException !!! prints out or not.
There are some examples of testing exception for a method
which throws an exception in its method ( ex. String method1() throws InterruptedException {...} ) in the Internet.
But not this case. Does anyone have some thought or idea?
public class A {
public List<String> getNames()
{
String addess = "address1";
int age = 17;
List<String> names = null;
try {
names = getSomeNames(address, sex);
}
catch (InterruptedException | ExecutionException e) {
throw new MyCustomException(e);
}
catch(Exception e) {
throw new MyCustomException(e);
}
return names;
}
List<String> getSomeNames(String address, int sex) throws InterruptedException, ExecutionException
{
// ...
// throw exceptions... at some point
//
return names;
}
}
public class MyCustomException extends Exception {
public MyCustomException(Throwable e) {
if (e.getCause() instanceof InterruptedException) {
// write log
System.out.println("Got InterruptedException !!!");
}
else if (e.getCause() instanceof ExecutionException) {
// write log
System.out.println("Got ExecutionException!!!");
}
else {
// write log
}
}
}
I tried this but the test failed and got NullPointerException in catch block.
#Test
public void testException() {
A objA = spy(new A());
try {
doThrow(MyCustomException.class).when(objA).getNames();
objA.getNnames();
}
catch (Exception e) {
System.out.println(e.getCause().toString()); // ==> throws java.lang.NullPointerException here.
}
}
There are several ways to test it.
First solution is to replace System.out with different stream and read from it later. ( I don't like this approach )
#Test
void whenSayHi_thenPrintlnCalled() throws IOException {
PrintStream normalOutput = System.out;
String result;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream temporalOutput = new PrintStream(baos)) {
System.setOut(temporalOutput);
ThatGuy thatGuy = new ThatGuy();
thatGuy.sayHi();
result = new String(baos.toByteArray(), StandardCharsets.UTF_8);
} finally {
System.setOut(normalOutput);
}
assertEquals("Hi", result.trim());
}
Second one is to use logger instead of just System.out. I consider this approach better not only from testing, but from code design perspective as well. Using this one you can just replace logger with Mockito.mock and user Mockito.verify to check what was called on your logger.
#Test
void whenSayHi_thenCallLogger() {
Logger logger = Mockito.mock(Logger.class);
ThatGuy thatGuy = new ThatGuy();
ReflectionTestUtils.setField(thatGuy, "logger", logger);
thatGuy.sayHiToLog();
verify(logger).error("Hi");
}
Class under testing looks like this:
class ThatGuy {
private static Logger logger = LoggerFactory.getLogger(ThatGuy.class);
void sayHi() {
System.out.println("Hi");
}
void sayHiToLog() {
logger.error("Hi");
}
}
I am trying to create a Spring Batch POC with Java Configuration and PostGreSQL.
I have successfully created beans that would have otherwise been provided via the in memory DB using #EnableBatchProcessing and #EnableAutoConfiguration.
I am not able to get the beans (JobExplorer) to return a JobExecution list given a JobInstance bean created from the same JobExplorer bean.
The error I am getting is "Unable to deserialize the execution context" which seems to be coming from the method trying to deserialize the "SHORT_CONTEXT" field of the JOB_EXECUTION_CONTEXT table.
I have passed the created JobExplorer bean DefaultExecutionContextSerializer. Later passed a DefaultLobHandler with "wrapAsLob" set to True when I was still getting the error.
#Bean
public JobRegistry jobRegistry() {
JobRegistry jr = new MapJobRegistry();
return jr;
}
#Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
JobRegistryBeanPostProcessor jrbpp = new JobRegistryBeanPostProcessor();
jrbpp.setJobRegistry(jobRegistry());
return jrbpp;
}
#Bean
public JobOperator jobOperator() {
SimpleJobOperator sjo = new SimpleJobOperator();
sjo.setJobExplorer(jobExplorer());
sjo.setJobLauncher(jobLauncher());
sjo.setJobRegistry(jobRegistry());
sjo.setJobRepository(jobRepository());
return sjo;
}
#Bean
public JobExplorer jobExplorer() {
JobExplorerFactoryBean jefb = new JobExplorerFactoryBean();
jefb.setDataSource(dataSource());
jefb.setJdbcOperations(jdbcTemplate);
jefb.setTablePrefix("batch_");
jefb.setSerializer(new DefaultExecutionContextSerializer());
DefaultLobHandler lh = new DefaultLobHandler();
lh.setWrapAsLob(true);
jefb.setLobHandler(lh);
JobExplorer je = null;
try {
je = jefb.getObject();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return je;
}
#ConfigurationProperties(prefix = "spring.datasource")
#Bean
#Primary
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean
public JobRepository jobRepository() {
JobRepositoryFactoryBean jrfb = new JobRepositoryFactoryBean();
jrfb.setDataSource(dataSource());
jrfb.setDatabaseType("POSTGRES");
jrfb.setTransactionManager(new ResourcelessTransactionManager());
jrfb.setSerializer(new DefaultExecutionContextSerializer());
jrfb.setTablePrefix("batch_");
JobRepository jr = null;
try {
jr = (JobRepository)jrfb.getObject();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return jr;
}
Below is the get method in my rest controller where I am trying handle generate a list of failed Job executions
#Autowired
JobLauncher jobLauncher;
#Autowired
JobRegistry jobRegistry;
#Autowired
JobOperator jobOperator;
#Autowired
JobExplorer jobExplorer;
#SuppressWarnings("unchecked")
#GetMapping("batch/failedJobs")
public Map<String, List<JobExecution>> getFailedJobs() {
try {
if (jobRegistry == null || jobOperator == null || jobExplorer == null) {
System.out.println("job registry, operator or explorer is null");
} else {
Map<String, List<JobExecution>> allJobInstances = new HashMap<String, List<JobExecution>>();
// Get all jobs
jobRegistry.getJobNames().stream().forEach(jobName -> {
jobExplorer.getJobInstances(jobName, 1, 1000).forEach(l -> {
System.out.println("jobName: " + jobName + " instance: " + l);
});
jobExplorer.getJobInstances(jobName, 1, 1000).stream().forEach(jobInstance -> {
List<JobExecution> execultionList = jobExplorer.getJobExecutions(jobInstance); //Failing here
if (execultionList != null) {
System.out.println("" + execultionList);
execultionList.stream().forEach(l2 -> {
System.out.println("jobName: " + jobName + " instance: " + jobInstance
+ " jobExecution: " + l2);
});
if(allJobInstances.get(jobName) == null) {
allJobInstances.put(jobName, new ArrayList<JobExecution>());
}
allJobInstances.get(jobName).addAll((Collection<? extends JobExecution>) jobExplorer.getJobExecutions(jobInstance).stream().filter(e -> e.getStatus().equals(BatchStatus.FAILED)));
}else {
System.out.println("Could not get jobExecution for jobName " + jobName + " jobInstance: " + jobInstance);
}
});
});
return allJobInstances;
}
}catch (Exception e) {
System.out.println(e.getMessage());
logger.info(e.getMessage());
}
return null;
}
I fixed a similar issue by changing to the Jackson2 serializer:
jefb.setSerializer(new Jackson2ExecutionContextStringSerializer());
You may try it.
I am using AndroidAnnotations and SQLite with ORMLite and am trying to get the database up and running. I was able to create the table and make a test-insert of a Contact object a few days ago.
However, I did some changes and then it stopped working - unfortunately I was not able to revert my changes and now I'm stuck and can't get it working anymore.
Whenever I start the app I get this error:
02-12 23:09:39.931 11766-11766/net.gazeapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: net.gazeapp, PID: 11766
java.lang.RuntimeException: Unable to start activity ComponentInfo{net.gazeapp/net.gazeapp.MainActivity_}: java.lang.NullPointerException: Attempt to invoke virtual method 'int net.gazeapp.data.ContactDao.create(java.lang.Object)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int net.gazeapp.data.ContactDao.create(java.lang.Object)' on a null object reference
at net.gazeapp.service.ContactService.addContact(ContactService.java:55)
at net.gazeapp.MainActivity.testNewORM(MainActivity.java:171)
at net.gazeapp.MainActivity.createView(MainActivity.java:148)
at net.gazeapp.MainActivity_.onViewChanged(MainActivity_.java:111)
at org.androidannotations.api.view.OnViewChangedNotifier.notifyViewChanged(OnViewChangedNotifier.java:41)
at net.gazeapp.MainActivity_.setContentView(MainActivity_.java:57)
at net.gazeapp.MainActivity_.onCreate(MainActivity_.java:45)
at android.app.Activity.performCreate(Activity.java:6251)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
So here is my MainActivity in which I do the ORM-testing (in the testNewORM() method):
#EActivity(R.layout.activity_main_viewpagertab)
#OptionsMenu(R.menu.menu_main)
public class MainActivity extends BaseActivity implements ObservableScrollViewCallbacks {
private final String TAG = getClass().getSimpleName();
private int mBaseTranslationY;
private NavigationAdapter mPagerAdapter;
private Contact mContact;
private static String[] tabTitles = null;
#App
GazeApplication application;
#ViewById(R.id.header)
View mHeaderView;
#ViewById(R.id.toolbar)
View mToolbarView;
#ViewById(R.id.pager)
ViewPager mPager;
#ViewById(R.id.fab)
FloatingActionButton fab;
#ViewById(R.id.adview)
MoPubView mAdView;
#Bean
ContactService contactService;
#AfterViews
void createView() {
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
Tools.readJsonFile(this, "fetishes.json");
// TAB TITLES: RECENT, ALL, MY MEDIA
tabTitles = new String[]{getString(R.string.recent), getString(R.string.all), getString(R.string.my_media)};
ViewCompat.setElevation(mHeaderView, getResources().getDimension(R.dimen.toolbar_elevation));
mPagerAdapter = new NavigationAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
SlidingTabLayout slidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs);
slidingTabLayout.setCustomTabView(R.layout.tab_indicator, android.R.id.text1);
slidingTabLayout.setSelectedIndicatorColors(getResources().getColor(R.color.colorAccent));
slidingTabLayout.setDistributeEvenly(true);
slidingTabLayout.setViewPager(mPager);
// When the page is selected, other fragments' scrollY should be adjusted
// according to the toolbar status(shown/hidden)
slidingTabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
propagateToolbarState(toolbarIsShown());
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
propagateToolbarState(toolbarIsShown());
displayAdBanner();
// TESTING ORMAPPER
// TESTING ORMAPPER
testNewORM();
}
void testNewORM() {
java.util.Date date = new java.util.Date();
Timestamp timeNow = new Timestamp(date.getTime());
Timestamp birthdateTimestamp = new Timestamp(date.getTime());
Date birthdate = new Date();
try {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
birthdate = dateFormat.parse("04/07/1980");
long time = birthdate.getTime();
birthdateTimestamp = new Timestamp(time);
} catch (ParseException e) {
e.printStackTrace();
}
Contact contact = new Contact("Dominik Erbsland");
contact.setBirthdate(birthdate);
try {
mContact = contactService.addContact(contact);
} catch (ItemNotFoundException | SQLException e) {
Log.e(TAG, e.getLocalizedMessage());
e.printStackTrace();
}
}
...
}
And here the other used classes:
#EBean(scope = EBean.Scope.Singleton)
public class ContactService {
private static final String TAG = ContactService.class.getSimpleName();
#RootContext
Context ctx;
#OrmLiteDao(helper = DatabaseHelper.class)
ContactDao mContactDao;
public Contact getContact(int contactId) throws ItemNotFoundException, SQLException {
Contact contact = mContactDao.queryForId(contactId);
if (contact == null) {
Log.e(TAG, "Contact not found in database");
throw new ItemNotFoundException();
}
return contact;
}
public List<Contact> getContacts() throws ItemNotFoundException, SQLException {
List<Contact> contact = mContactDao.queryForAll();
if (contact == null) {
Log.e(TAG, "Contacts not found in database");
throw new ItemNotFoundException();
}
return contact;
}
public Contact addContact(Contact contact) throws SQLException {
int rowsAffected = 0;
try {
rowsAffected = mContactDao.create(contact);
} catch (SQLException e) {
Log.e(TAG, e.getLocalizedMessage());
e.printStackTrace();
}
Log.d(TAG, "New Contact ID: " + contact.getId());
return contact;
}
public void testOutput() {
Log.d(TAG, "THIS IS A TEST OUTPUT");
}
}
here my database helper:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final String DATABASE_NAME = "Gaze.db";
private static final int DATABASE_VERSION = 1;
private final Context context;
// the DAO object we use to access the Person table
private Dao<Contact, Integer> contactDao = null;
private Dao<MyPreferences, Integer> preferencesDao = null;
private Dao<SecurityQuestion, Integer> securityQuestionDao = null;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
/**
* This is called when the database is first created. Usually you should call createTable statements here to create
* the tables that will store your data.
*/
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
try {
Log.i(DatabaseHelper.class.getName(), "onCreate");
TableUtils.createTable(connectionSource, Contact.class);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Can't create database", e);
throw new RuntimeException(e);
}
}
/**
* This is called when your application is upgraded and it has a higher version number. This allows you to adjust
* the various data to match the new version number.
*/
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
try {
Log.i(DatabaseHelper.class.getName(), "onUpgrade");
TableUtils.dropTable(connectionSource, Contact.class, true);
// after we drop the old databases, we create the new ones
onCreate(db, connectionSource);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e);
throw new RuntimeException(e);
}
}
/**
* Returns the Database Access Object (DAO) for our Person class. It will create it or just give the cached
* value.
*/
public Dao<Contact, Integer> getContactDao() throws SQLException {
if (contactDao == null) {
contactDao = getDao(Contact.class);
}
return contactDao;
}
public Dao<MyPreferences, Integer> getPreferencesDao() throws SQLException {
if (preferencesDao == null) {
preferencesDao = getDao(MyPreferences.class);
}
return preferencesDao;
}
public Dao<SecurityQuestion, Integer> getSecurityQuestionDao() throws SQLException {
if (securityQuestionDao == null) {
securityQuestionDao = getDao(SecurityQuestion.class);
}
return securityQuestionDao;
}
/**
* Close the database connections and clear any cached DAOs.
*/
#Override
public void close() {
super.close();
contactDao = null;
preferencesDao = null;
securityQuestionDao = null;
}
}
and the data class:
#DatabaseTable(tableName = "Contact", daoClass = ContactDao.class)
public class Contact implements Serializable {
#DatabaseField(generatedId = true, columnName = PersistentObject.ID)
int id;
#DatabaseField(index = true)
String contactName;
#DatabaseField
String mainPic;
#DatabaseField(dataType = DataType.DATE_STRING, format = "yyyy-MM-dd HH:mm:ss.S")
Date birthdate;
#DatabaseField
boolean knowPersonally;
#DatabaseField(dataType = DataType.DATE_STRING, format = "yyyy-MM-dd HH:mm:ss.S")
Timestamp created;
#DatabaseField(dataType = DataType.DATE_STRING, format = "yyyy-MM-dd HH:mm:ss.S")
Timestamp lastMod;
public Contact() {
// needed by ormlite
}
...
}
and the ContactDao:
public class ContactDao extends BaseDaoImpl<Contact, Integer> {
public ContactDao(Class<Contact> dataClass) throws SQLException {
super(dataClass);
}
public ContactDao(ConnectionSource connectionSource, Class<Contact> dataClass) throws SQLException {
super(connectionSource, dataClass);
}
public ContactDao(ConnectionSource connectionSource, DatabaseTableConfig<Contact> tableConfig) throws SQLException {
super(connectionSource, tableConfig);
}
public List<Contact> getContacts() throws SQLException {
return queryForAll();
}
}
So in the ContactService class at "mContactDao.create(contact);" it crashed with the Exception. This is the part I don't understand because ContactService is annotated with #EBean and is being accessed in MainActivity with "#Bean
ContactService contactService;" and shouldn't be null there...
Thanks for any help or hints in advance.
The problem is the following:
The code is trying to access the mContactDao field, but it is indeed null, altough it should be injected by AndroidAnnotations. But the field cannot be injected, because the dao creation fails with an exception. This is logged by AndroidAnnotations, you can check it in LogCat.
The cause of the problem lies in the Contact class. You are using List<Something> fields, but ORMLite does not know how to persist the java.util.List object. You can either use a custom persister, or you can use foreign fields:
Contact.java:
#ForeignCollectionField
private ForeignCollection<Address> adresses;
Update:
Applying the ForestCollectionField changes and debugging again showed another problem. The DataType.DATE_STRING persister cannot be used with the java.sql.Timestamp class. But you can use DataType.TIME_STAMP instead:
#DatabaseField(dataType = DataType.TIME_STAMP, format = "yyyy-MM-dd HH:mm:ss.S")
Timestamp created;
#DatabaseField(dataType = DataType.TIME_STAMP, format = "yyyy-MM-dd HH:mm:ss.S")
Timestamp lastMod;
I have a problem with Titan 0.5.1. I try to upgrade Titan 0.4.4 to 0.5.1. Currently, I use berkeleyje and i configure like this :
BaseConfiguration conf = new BaseConfiguration();
// Storage info
conf.setProperty("storage.directory", directory + File.separator + DB_NAME);
conf.setProperty("storage.backend", "berkeleyje");
// Class info storage
conf.setProperty("attributes.allow-all", "true");
conf.setProperty("attributes.custom.attribute1.attribute-class", "model.Property");
conf.setProperty("attributes.custom.attribute1.serializer-class", "PropertySerializer");
TitanGraph graph = TitanFactory.open(conf);
For serialize my object i use :
public class PropertySerializer implements AttributeSerializer<Property> {
#Override
public Property read(ScanBuffer buffer) {
Property object = null;
ArrayList<Byte> records = new ArrayList<Byte>();
try {
while (buffer.hasRemaining()) {
records.add(Byte.valueOf(buffer.getByte()));
}
Byte[] bytes = records.toArray(new Byte[records.size()]);
ByteArrayInputStream bis = new ByteArrayInputStream(ArrayUtils.toPrimitive(bytes));
ObjectInput in = new ObjectInputStream(bis);
object = (Property) in.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
#Override
public void write(WriteBuffer out, Property attribute) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput outobj;
outobj = new ObjectOutputStream(bos);
outobj.writeObject(attribute);
byte[] propertybyte = bos.toByteArray();
for (int i = 0; i < propertybyte.length; i++) {
out.putByte(propertybyte[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void verifyAttribute(Property value) {
// TODO Auto-generated method stub
}
#Override
public Property convert(Object value) {
// TODO Auto-generated method stub
return null;
}
}
Typically, i add a property like this :
Vertex r = this.model.addVertex(null);
Property p = new Property();
r.setProperty("object", p);
this.model.commit();
But i obtain this error :
Exception in thread "main"
com.thinkaurelius.titan.core.TitanException: Could not commit
transaction due to exception during persistence at
com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx.commit(StandardTitanTx.java:1310)
at
com.thinkaurelius.titan.graphdb.blueprints.TitanBlueprintsGraph.commit(TitanBlueprintsGraph.java:60)
Caused by: com.thinkaurelius.titan.core.TitanException: Serializer
Restriction: Cannot serialize object of type: class
.model.Property at
com.thinkaurelius.titan.graphdb.database.serialize.StandardSerializer$StandardDataOutput.writeClassAndObject(StandardSerializer.java:160)
at
com.thinkaurelius.titan.graphdb.database.EdgeSerializer.writePropertyValue(EdgeSerializer.java:383)
at
com.thinkaurelius.titan.graphdb.database.EdgeSerializer.writePropertyValue(EdgeSerializer.java:377)
at
com.thinkaurelius.titan.graphdb.database.EdgeSerializer.writeRelation(EdgeSerializer.java:293)
at
com.thinkaurelius.titan.graphdb.database.StandardTitanGraph.prepareCommit(StandardTitanGraph.java:485)
at
com.thinkaurelius.titan.graphdb.database.StandardTitanGraph.commit(StandardTitanGraph.java:613)
at
com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx.commit(StandardTitanTx.java:1299)
Can you help me please ? Because, with 0.4.4 version it worked. The new documentation don't help me.
Thanks in advance