I have a problem with my MVC application that displays data in a JTable. Everything worked fine, but I decided to add a SwingWorker to retrieve data from the database.
My controller calls the model with data from the database. It looks like this.
Model.java
public class Model {
private List<Category> people = new Vector<Category>();
public List<Category> getPeople() {
return new ArrayList<Category>(people);
}
public void load() throws Exception {
people.clear();
DAOFactory factory = DAOFactory.getFactory(DAOFactory.MYSQL);
CategoryDAO personDAO = factory.getCategoryDAO();
people.addAll(personDAO.getCategory());
}
}
I add SwingWorker to getCategory class
MySQLCategodyDAO.java
public class MySQLCategoryDAO extends SwingWorker<Void, Vector<Object>> implements CategoryDAO{
private Job job;
private List<Category> cat;
public MySQLCategoryDAO(Job job){
this.job = job;
}
#Override
protected Void doInBackground() throws Exception {
// TODO Auto-generated method stub
if(job == Job.SELECT){
getCategory();
System.out.println("Table selected");
}
return null;
}
#Override()
public void done(){
}
public List<Category> getCategory() throws SQLException
{
cat = new ArrayList<Category>();
Connection conn = Database.getInstance().getConnection();
System.out.println(conn);
String sql = "select id, name from kategorie";
Statement selectStatement = conn.createStatement();
ResultSet results = selectStatement.executeQuery(sql);
while(results.next())
{
int id = results.getInt("id");
String name = results.getString("name");
Category category = new Category(id, name);
cat.add(category);
}
results.close();
selectStatement.close();
return cat;
}
}
View just retrieves the data from the model:
people = model.getPeople();
for (Category person : people) {
tablemodel
.addRow(new Object[] { person.getId(), person.getName() });
}
The problem comes when you call SwingWorker in class Model.java
public void load() throws Exception {
people.clear();
DAOFactory factory = DAOFactory.getFactory(DAOFactory.MYSQL);
CategoryDAO personDAO = factory.getCategoryDAO();
people.addAll(new MySQLCategoryDAO(Job.SELECT).execute()); - ERROR
}
Error:-
The method addAll(Collection<? extends Category>) in the type List<Category> is not applicable for the
arguments (void)
I know SwingWorker returns nothing, because there is an error. I should write the code in the method done(), but I have no idea how to solve it.
execute does not have a return value so it can't be used in the way you are trying to use it. The idea of SwingWorker is that the task should be executed asynchronously so you need to rework your design.
The SwingWorker bears a result (the List<Category>) and you either need to:
put the result somewhere from inside the SwingWorker (such as with the publish mechanism)
or call get from the outside to wait for the task to finish and return.
Here is the tutorial for review: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Quick example:
class MySQLCategoryDAO extends SwingWorker<Void, Category> {
// ...
private List<Category> list; // do not modify inside doInBackground
MySQLCategoryDAO(Job job, List<Category> list) {
this.list = list;
// ...
}
#Override
protected Void doInBackground() {
// ...
while(results.next()) {
int id = results.getInt("id");
String name = results.getString("name");
publish(new Category(id, name)); // publish results to the EDT
}
// ...
return null;
}
#Override
protected void process(List<Category> chunks) {
list.addAll(chunks); // add results to the list on the EDT
// add to the JTable (?)
}
}
public void load() throws Exception {
people.clear();
DAOFactory factory = DAOFactory.getFactory(DAOFactory.MYSQL);
CategoryDAO personDAO = factory.getCategoryDAO();
// just execute
new MySQLCategoryDAO(Job.SELECT, people).execute();
}
If you want to populate the entire table at once then you can also publish a List after the loop instead of one Category at a time. process would receive a List<List<Category>> with a singular element.
Sorry my mistake.
From the view gets to model.getPeople (), but nothing is returned. I did a test:
But nothing is returned
public class Model {
private List<Category> people = new Vector<Category>();
public List<Category> getPeople() {
for (Category person : people) {
System.out.println(person.getName()); //no data
}
return new ArrayList<Category>(people);
}
public void load() throws Exception {
people.clear();
DAOFactory factory = DAOFactory.getFactory(DAOFactory.MYSQL);
new MySQLCategoryDAO(Job.SELECT,people).execute();
}
}
Related
I'm developing this application to fetch data from a single table from an existing Oracle database.
Here we've got the entity:
public class OrdemDeServicoCount {
private Long ordensInternas;
private Long ordensAtrasadas;
// assume getters and setters
}
The mapper:
public class OrdemMapper implements RowMapper<OrdemDeServicoCount> {
#Override
public OrdemDeServicoCount mapRow(ResultSet rs, int rowNum) throws SQLException {
OrdemDeServicoCount ordens = new OrdemDeServicoCount();
ordens.setOrdensInternas(rs.getLong("ordensInternas"));
// ordens.setOrdensAtrasadas(rs.getLong("ordensAtrasadas"));
return ordens;
}
}
And finally, the DAO:
public class OrdemDAO {
private JdbcTemplate jdbcTemplate;
public OrdemDAO(JdbcTemplate jdbcTemplate) {
super();
this.jdbcTemplate = jdbcTemplate;
}
public List<OrdemDeServicoCount> countOrdensInternasSemEncerrar() {
String sql = "SELECT COUNT(a.nr_sequencia) AS ordensInternas FROM MAN_ORDEM_SERVICO a "
+ "WHERE a.IE_STATUS_ORDEM IN (1,2) AND a.NR_GRUPO_PLANEJ IN (21)";
List<OrdemDeServicoCount> ordens = jdbcTemplate.query(sql, new OrdemMapper());
return ordens;
}
By the way, you all must know that if I declare uncomment the line ordens.setOrdensInternas(rs.getLong("ordensInternas")); in the mapper, I would get an error, because in my DAO, I'm not using that field.
But what if I need to create another method that uses just the ordensInternas field? Then again, I'd get an error...
So, my doubt here is: if I need to use the ordensAtrasadas field from the entity, will I have to create another class just to implement another mapper? Or is there a way that I can do any conditional in my current OrdemMapper class?
Just put your assignments in individual try-catch statements.
public class OrdemMapper implements RowMapper<OrdemDeServicoCount> {
#Override
public OrdemDeServicoCount mapRow(ResultSet rs, int rowNum) throws SQLException {
OrdemDeServicoCount ordens = new OrdemDeServicoCount();
try {
ordens.setOrdensInternas(rs.getLong("ordensInternas"));
} catch (SQLException ex) {
// This will happen if the columnIndex is invalid among other things
}
try {
ordens.setOrdensAtrasadas(rs.getLong("ordensAtrasadas"));
} catch (SQLException ex) {
// This will happen if the columnIndex is invalid among other things
}
return ordens;
}
}
I created a room database following this guide from code labs It makes use of a repository to:
A Repository manages query threads and allows you to use multiple backends. In the most common example, the Repository implements the logic for deciding whether to fetch data from a network or use results cached in a local database.
I followed the guide and i'm now able to create the entity's & retrieve the data. I even went further and created another whole entity outside the scope of the guide.
However I can't find many resources that use this MVVM(?) style so am struggling as to really under stand the repository. For now I want to update a field. Just one, as if I am able to manage that the rest should be similar.
I want to update a field called dartshit and I have the dao method created for this:
#Query("UPDATE AtcUserStats SET dartsHit = :amount WHERE userName = :userName")
void UpdateHitAmount(int amount, String userName);
I have one repository which I assumed I use for all entities:
public class UsersRepository {
private UsersDao mUsersDao;
private AtcDao mAtcDao;
private LiveData<List<Users>> mAllUsers;
private LiveData<List<AtcUserStats>> mAllAtc;
private AtcUserStats mAtcUser;
UsersRepository(Application application) {
AppDatabase db = AppDatabase.getDatabase(application);
mUsersDao = db.usersDao();
mAtcDao = db.atcDao();
mAllUsers = mUsersDao.fetchAllUsers();
mAllAtc = mAtcDao.getAllAtcStats();
}
LiveData<List<Users>> getAllUsers() {
return mAllUsers;
}
LiveData<List<AtcUserStats>> getAllAtcStats() {
return mAllAtc;
}
LiveData<AtcUserStats> getAtcUser(String username) {
return mAtcDao.findByName(username);
}
public void insert (Users user) {
new insertAsyncTask(mUsersDao).execute(user);
}
public void insertAtc (AtcUserStats atc) {
new insertAsyncAtcTask(mAtcDao).execute(atc);
}
private static class insertAsyncTask extends AsyncTask<Users, Void, Void> {
private UsersDao mAsyncTaskDao;
insertAsyncTask(UsersDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected Void doInBackground(final Users... params) {
mAsyncTaskDao.insertNewUser(params[0]);
return null;
}
}
private static class insertAsyncAtcTask extends AsyncTask<AtcUserStats, Void, Void> {
private AtcDao mAsyncTaskDao;
insertAsyncAtcTask(AtcDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected Void doInBackground(final AtcUserStats... params) {
mAsyncTaskDao.insertNewAtcUser(params[0]);
return null;
}
}
}
My question is how do I create a AsyncTask for the update query I am trying to run in this repository?
Here is what I have so far by broadly copying the insert repository methods:
private class updateHitAsyncTask {
private AtcDao mAsyncTaskDao;
public updateHitAsyncTask(AtcDao mAtcDao) {
mAsyncTaskDao = mAtcDao;
}
protected Void doInBackground(int amount, String name) {
mAsyncTaskDao.UpdateHitAmount(amount, name);
return null;
}
}
Which is incorrect is that I'm getting a llegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. error. But i thought this AsyncTask is suppose to take care of this?
Here is my update method in my view model, which is reporting 0 errors:
void updateHitAmount (int amount, String name) {
mRepository.updateAtcHits(amount, name);
}
and here is the UI code where im actually trying to tie all these together, I suspect there must be a better way that using onChanged for simply updating a field but again I am struggling to come across any advice on google with the repository approach:
private void callOnChanged() {
mAtcViewModel = ViewModelProviders.of(this).get(AtcViewModel.class);
mAtcViewModel.getAllUsers().observe(this, new Observer<List<AtcUserStats>>() {
#Override
public void onChanged(#Nullable final List<AtcUserStats> atc) {
// Update the cached copy of the users in the adapter.
for (int i = 0; i < atc.size(); i++) {
if (atc.get(i).getUserName().equals(mUser)) {
mAtcViewModel.updateHitAmount(55, mUser);
//atc.get(i).setDartsHit(55);
Log.d("id", String.valueOf(userSelected.getId()));
}
}
}
});
How can I update fields using this approach on the background thread?
Figured it out due to this answer here. It was mostly because of my lack of understanding of AsyncTask. Essentially I needed to create an object and pass the data that way and then execute in the background:
private static class MyTaskParams {
int amount;
String name;
MyTaskParams(int amount, String name) {
this.amount = amount;
this.name = name;
}
}
public void updateAtcHits (int amount, String name) {
MyTaskParams params = new MyTaskParams(amount,name);
new updateHitAsyncTask(mAtcDao).execute(params);
}
private class updateHitAsyncTask extends AsyncTask<MyTaskParams,Void,Void>{
private AtcDao mAsyncTaskDao;
public updateHitAsyncTask(AtcDao mAtcDao) {
mAsyncTaskDao = mAtcDao;
}
#Override
protected Void doInBackground(MyTaskParams... myTaskParams) {
int amount =myTaskParams[0].amount;
String name = myTaskParams[0].name;
mAsyncTaskDao.UpdateHitAmount(amount, name);
return null;
}
}
How to pass value from one class to jcombobox in another class
Public void getItem (){
try {
dBconnection...
while(rs.next){
String customers = rs.getString (1);
this.jcombobox1.addItem (customers);
}
}
}
From this method to jcombobox in another class. The error is in jcombobox?
Since you are already having B's class object in A lets say ex Bclassobj.
Public void getItem (){
try {
while(rs.next){
this.jcombobox1.addItem (rs.getString (1));
Bclassobj.Bclassjcombobox.addItem (rs.getString (1));
}
}
}
Generally this is a poor way of coding, no offense.
You should not mix the code for:
Getting the connection to database
Executing some SQL command and fetching data from ResultSet
Creating graphics
Simply change your method Public void getItem () to Public List<String> getCustomers(). This method's business should be just fetching the data from database, and returning the list of Customer's names as List<String>.
Then in your another class, simply call this method and set the whole List<String> as the model of your JComboBox.
See the example below:
public class AnotherClass extends JFrame{
private JComboBox<String> jComboBox;
public AnotherClass() {
init();
}
private void init(){
//... other components
DBClass db = new DBClass();
List<String> customers = db.getCustomers();
jComboBox = new JComboBox<>(customers.toArray(new String[]{}));
this.add(jComboBox);
//... other components
}
}
class DBClass{
public List<String> getCustomers (){
List<String> customers = new ArrayList<>();
try{
//dBconnection...
ResultSet rs = null;// your code for getting ResultSet
while(rs.next()){
String customer = rs.getString (1);
customers.add(customer);
}
}catch(SQLException e){
e.printStackTrace();
}
return customers;
}
}
Good Luck.
Could you guys please help me find where I made a mistake ?
I switched from SimpleBeanEditorDriver to RequestFactoryEditorDriver and my code no longer saves full graph even though with() method is called. But it correctly loads full graph in the constructor.
Could it be caused by circular reference between OrganizationProxy and PersonProxy ? I don't know what else to think :( It worked with SimpleBeanEditorDriver though.
Below is my client code. Let me know if you want me to add sources of proxies to this question (or you can see them here).
public class NewOrderView extends Composite
{
interface Binder extends UiBinder<Widget, NewOrderView> {}
private static Binder uiBinder = GWT.create(Binder.class);
interface Driver extends RequestFactoryEditorDriver<OrganizationProxy, OrganizationEditor> {}
Driver driver = GWT.create(Driver.class);
#UiField
Button save;
#UiField
OrganizationEditor orgEditor;
AdminRequestFactory requestFactory;
AdminRequestFactory.OrderRequestContext requestContext;
OrganizationProxy organization;
public NewOrderView()
{
initWidget(uiBinder.createAndBindUi(this));
requestFactory = createFactory();
requestContext = requestFactory.contextOrder();
driver.initialize(requestFactory, orgEditor);
String[] paths = driver.getPaths();
createFactory().contextOrder().findOrganizationById(1).with(paths).fire(new Receiver<OrganizationProxy>()
{
#Override
public void onSuccess(OrganizationProxy response)
{
if (response == null)
{
organization = requestContext.create(OrganizationProxy.class);
organization.setContactPerson(requestContext.create(PersonProxy.class));
} else
organization = requestContext.edit(response);
driver.edit(organization, requestContext);
}
#Override
public void onFailure(ServerFailure error)
{
createConfirmationDialogBox(error.getMessage()).center();
}
});
}
private static AdminRequestFactory createFactory()
{
AdminRequestFactory factory = GWT.create(AdminRequestFactory.class);
factory.initialize(new SimpleEventBus());
return factory;
}
#UiHandler("save")
void buttonClick(ClickEvent e)
{
e.stopPropagation();
save.setEnabled(false);
try
{
AdminRequestFactory.OrderRequestContext ctx = (AdminRequestFactory.OrderRequestContext) driver.flush();
if (!driver.hasErrors())
{
// Link to each other
PersonProxy contactPerson = organization.getContactPerson();
contactPerson.setOrganization(organization);
String[] paths = driver.getPaths();
ctx.saveOrganization(organization).with(paths).fire(new Receiver<Void>()
{
#Override
public void onSuccess(Void arg0)
{
createConfirmationDialogBox("Saved!").center();
}
#Override
public void onFailure(ServerFailure error)
{
createConfirmationDialogBox(error.getMessage()).center();
}
});
}
} finally
{
save.setEnabled(true);
}
}
}
with() is only used for retrieval of information, so your with() use with a void return type is useless (but harmless).
Whether a full graph is persisted is entirely up to your server-side code, which is intimately bound to your persistence API (JPA, JDO, etc.)
First, check that the Organization object you receive in your save() method on the server-side is correctly populated. If it's not the case, check your Locators (and/or static findXxx methods) ; otherwise, check your save() method's code.
Judging from the code above, I can't see a reason why it wouldn't work.
It took me some time to realize that the problem was the composite id of Person entity.
Below is the code snippet of PojoLocator that is used by my proxy entities.
public class PojoLocator extends Locator<DatastoreObject, Long>
{
#Override
public DatastoreObject find(Class<? extends DatastoreObject> clazz, Long id)
{
}
#Override
public Long getId(DatastoreObject domainObject)
{
}
}
In order to fetch child entity from DataStore you need to have id of a parent class. In order to achieve that I switched "ID class" for Locator<> to String which represents textual form of Objectify's Key<> class.
Here is how to looks now:
public class PojoLocator extends Locator<DatastoreObject, String>
{
#Override
public DatastoreObject find(Class<? extends DatastoreObject> clazz, String id)
{
Key<DatastoreObject> key = Key.create(id);
return ofy.load(key);
}
#Override
public String getId(DatastoreObject domainObject)
{
if (domainObject.getId() != null)
{
Key<DatastoreObject> key = ofy.fact().getKey(domainObject);
return key.getString();
} else
return null;
}
}
Please note that your implementation may slightly differ because I'm using Objectify4.
I'm building a test, in which I need to send question, and wait for the answer.
Message passing is not the problem. In fact to figure out which answer corresponds to which question, I use an id. My id is generated using an UUID. I want to retrieve this id, which is given as a parameter to a mocked object.
It look like this:
oneOf(message).setJMSCorrelationID(with(correlationId));
inSequence(sequence);
Where correlationId is the string I'd like to keep for an other expectation like this one:
oneOf(session).createBrowser(with(inputChannel),
with("JMSType ='pong' AND JMSCorrelationId = '"+correlationId+"'"));
have you got an answer?
You have to create your own actions. Here is mine:
/**
* puts the parameter array as elements in the list
* #param parameters A mutable list, will be cleared when the Action is invoked.
*/
public static Action captureParameters(final List<Object> parameters) {
return new CustomAction("captures parameters") {
public Object invoke(Invocation invocation) throws Throwable {
parameters.clear();
parameters.addAll(Arrays.asList(invocation.getParametersAsArray()));
return null;
}
};
}
You then use it like this (with a static import):
final List<Object> parameters = new ArrayList<Object>();
final SomeInterface services = context.mock(SomeInterface.class);
context.checking(new Expectations() {{
oneOf(services).createNew(with(6420), with(aNonNull(TransactionAttributes.class)));
will(doAll(captureParameters(parameters), returnValue(true)));
}});
To do what you want, you have to implement your own matcher. This is what I hacked up (some null checking left out, and of course I just use well known interfaces for the sample):
#RunWith(JMock.class)
public class Scrap {
private Mockery context = new JUnit4Mockery();
#Test
public void testCaptureParameters() throws Exception {
final CharSequence mock = context.mock(CharSequence.class);
final ResultSet rs = context.mock(ResultSet.class);
final List<Object> parameters = new ArrayList<Object>();
context.checking(new Expectations(){{
oneOf(mock).charAt(10);
will(doAll(JMockActions.captureParameters(parameters), returnValue((char) 0)));
oneOf(rs).getInt(with(new ParameterMatcher<Integer>(parameters, 0)));
}});
mock.charAt(10);
rs.getInt(10);
}
private static class ParameterMatcher<T> extends BaseMatcher<T> {
private List<?> parameters;
private int index;
private ParameterMatcher(List<?> parameters, int index) {
this.parameters = parameters;
this.index = index;
}
public boolean matches(Object item) {
return item.equals(parameters.get(index));
}
public void describeTo(Description description) {
description.appendValue(parameters.get(index));
}
}
}
One more option to consider, where does the correlation ID come from? Should that activity be injected in so that you can control it and check for it in the test?
i found out an other solution on this site
http://www.symphonious.net/2010/03/09/returning-parameters-in-jmock-2/
import org.hamcrest.*;
import org.jmock.api.*;
public class CapturingMatcher<T> extends BaseMatcher<T> implements Action {
public T captured;
public boolean matches(Object o) {
try {
captured = (T)o;
return true;
} catch (ClassCastException e) {
return false;
}
}
public void describeTo(Description description) {
description.appendText("captured value ");
description.appendValue(captured);
}
public Object invoke(Invocation invocation) throws Throwable {
return captured;
}
}
It can then be used like:
context.checking(new Expectations() {{
CapturingMatcher<String> returnCapturedValue = new CapturingMatcher<String>();
allowing(mockObject).getParameter(with(equal("expectedParameterName")), with(returnCapturedValue)); will(returnCapturedValue);
}});