How can i update a field of a ListItem?
I have following POJO and ViewModel classes. Currently i am getting the complete list from LiveData object and then updating its data then re-setting the value of LiveData object, But I don't think this is the correct way to do it because to update just name of a single book i have to reset the complete LiveData Object.
Any other suggestion or Good practice to do it the correct way?
public class Book {
private long id;
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class BookProvider extends AndroidViewModel {
private final MutableLiveData<List<Book>> booksData;
public BookProvider(#NonNull Application application) {
super(application);
booksData = new MutableLiveData<>();
}
public LiveData<List<Book>> getBooksData() {
return booksData;
}
public void updateBookName(int position, String name) {
final List<Book> books = booksData.getValue();
if (books != null && books.size() > position) {
books.get(position).setName(name);
}
booksData.setValue(books);
}
}
LiveData is just a container holding a reference to your data and notifying possible observer of changes. So as far as LiveData is concerned this is the best you can do.
However LiveData does't support molecular changes so every change may results in the entire list invalidating and redrawn. It is strongly suggested that you use a different method if you have lot of changes in data (like real-time applications).
Related
I created a POJO model and did not call it out.
This is the code to run it.
DataObjectSelectGarage selectGarage = ...;
TextView.setText(selectGarage.getGaragename());
Do not know if it can run this way?
this is model
public class DataObjectSelectGarage implements Serializable {
#SerializedName("Garage_id")
private int id;
public int getGarage_id() {
return id;
}
public void setgetGarage_id(String getGarage_id) {
this.id = id;
}
#SerializedName("Garagename")
private String name;
public String getGaragename() {
return name;
}
public void setGaragename(String name) {
this.name = name;
}
}
public void setgetGarage_id(String getGarage_id) {
this.id = id;
}
The above set method assigning Id = id instead of id= getGarage_id
This cannot work this way
DataObjectSelectGarage selectGarage;
TextView.setText(selectGarage.getGaragename());
As DataObjectSelectGarage is not initialized. You need to initialize it first.
Secondly in code you posted there are multiple logical bugs like you are passing UserId to HTTP request param without assigning value to it. Secondly without pasring response trying to present it to user.
#Override
public void onResponse(String response) {
/*DataObjectSelectGarage dataObjectSelectGarage = new
DataObjectSelectGarage();
String test1 = dataObjectSelectGarage.getGaragename();*/
tvTest.setText(selectGarage.getGaragename());
Log.d("Selectgarage",response.toString());
}
you need to parse the response string and then after initializing model object and setting values in it use it to show data on view.
What is good practice to create pojo as having Class fields or simple fields.
I am creating pojo like this.
public class StatusDTO {
private String id;
private int totalNodes;
private int totalServlets;
private boolean status;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getTotalNodes() {
return totalNodes;
}
public void setTotalNodes(int totalNodes) {
this.totalNodes = totalNodes;
}
public int getTotalServlets() {
return totalServlets;
}
public void setTotalServlets(int totalServlets) {
this.totalServlets = totalServlets;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
}
someone recommanded me to do like this as below
public class StatusDTO {
private String id;
private boolean status;
private Total total;
public Total getTotal() {
return total;
}
public void setTotal(Total total) {
this.total = total;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public static class Total {
private int nodes;
private int servlets;
public int getNodes() {
return nodes;
}
public void setNodes(int nodes) {
this.nodes = nodes;
}
public int getServlets() {
return servlets;
}
public void setServlets(int servlets) {
this.servlets = servlets;
}
}
}
what difference does it make? what is good practice among those two?
I am using this class to set db info and send info to web socket client(stomp)
The answer, as always in such questions, is: It depends.
Simple classes like the first one have the advantage that they are simpler and smaller. The advantage on the second attempt is that if your class, maybe now, maybe later, gets extended, it might be easier if you create a separate Total class.
Good Objectoriented Programming, and Java is strongly OO, almost always requires you to put everything into it's own class.
As a rule of thumb, I create a separate class if:
there is some functionality you to your fields.
you have more then two, mabye three fields related to each other (e.g. connectionHost, connectionPort)
it's just a model class (e.g. Customer, Article)
I can use the field in multiple other classes
Of course there are more but those are some of the most important ones (comment if you think there is another important one I forgot to mention).
Well, one important thing in a good Java application is separation of concerns, for example in an airport application a service that give the last flight of a customer should not require as parameter an object with the first name, the last name, the social security number, the marital status, the gender or whatever other information about the customer that are completely useless (or should be) in retrieving the customer last flight, such that you need to have an object Customer (with all customer information) and another object CustomerId (with only the necessary bits to get the flights).
Another example is for a online shop application, a service that calculate the total price of the basket should not require all the information about all articles (photos, description, specifications, ...) in the basket but only the prices and the discounts which should be enclosed in another object.
Here you have to decide if the concerns of your Total (you need a better name) object could be taken separately of the concerns of your StatusDTO object, such that a method could require only the Total object without the associated StatusDTO object. If you can take them separately then you should have separate objects, if you can't then it's unnecessary.
So, while developing an app, I have to use event sourcing to track down all changes to model. The app itself is made using spring framework. The problem I encountered: for example, user A sends a command to delete an entity and it takes 1 second to complete this task. User B, at the same time, sends a request to modify, for example, an entity name and it takes 2 seconds to do so. So my program finishes deleting this entity (persisting an event that says this entity is deleted), and after it another event is persisted for the same entity, that says that we just modified its name. But no actions are allowed with deleted entities. Boom, we just broke the app logic. It seems to me, that I have to put methods that write to database in synchronized blocks, but is there are any other way to handle this issue? Like, I dunno, queuing events? The application is not huge, and not a lot of requests are expected, so users can wait for its request turn in the queue (of course I can return 202 HTTP Status Code to him, but like I said, requests are not resource heavy and there wont be a lot of them, so its unnecessary). So what is the best way for me to use here?
EDIT: Added code to illustrate the problem. Is using synchronized in this case is a good practice or there are other choices?
#RestController
#RequestMapping("/api/test")
public class TestController {
#Autowired
private TestCommandService testCommandService;
#RequestMapping(value = "/api/test/update", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void update(TestUpdateCommand command) {
testCommandService.update(command);
}
#RequestMapping(value = "/api/test/delete", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void delete(Long id) {
testCommandService.delete(id);
}
}
public class TestUpdateCommand {
private Long id;
private String name;
public TestUpdateCommand() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface TestCommandService {
void delete(Long id);
void update(TestRegisterCommand command);
}
#Service
public class TestCommandServiceImpl implements TestCommandService {
#Autowired
TestEventRepository testEventRepository;
#Override
#Transactional
public void delete(Long id) {
synchronized (TestEvent.class) {
//do logic, check if data is valid from the domain point of view. Logic is also in synchronized block
DeleteTestEvent event = new DeleteTestEvent();
event.setId(id);
testEventRepository.save(event);
}
}
#Override
#Transactional
public void update(TestUpdateCommand command) {
synchronized (TestEvent.class) {
//do logic, check if data is valid from the domain point of view. Logic is also in synchronized block
UpdateTestEvent event = new DeleteTestEvent();
event.setId(command.getId());
event.setName(command.getName());
testEventRepository.save(event);
}
}
}
#Entity
public abstract class TestEvent {
#Id
private Long id;
public Event() {
}
public Event(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
#Entity
public class DeleteTestEvent extends TestEvent {
}
#Entity
public class UpdateTestEvent extends TestEvent {
private String name;
public UpdateTestEvent() {
}
public UpdateTestEvent(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface TestEventRepository extends JpaRepository<TestEvent, Long>{
}
Make sure you read Don't Delete -- Just Don't by Udi Dahan.
I have to put methods that write to database in synchronized blocks, but is there are any other way to handle this issue?
Yes, but you have to be careful about identifying what the issue is...
In the simple version; as you have discovered, allowing multiple sources of "truth" can introduce a conflict. Synchronization blocks is one answer, but scaling synchronization is challenging.
Another approach is to use a "compare and swap approach" -- each of your writers loads the "current" copy of the state, calculates changes, and then swaps the new state for the "current" state. Imagine two writers, one trying to change state:A to state:B, and one trying to change state:A to state:C. If the first save wins the race, then the second save fails, because (A->C) isn't a legal write when the current state is B. The second writer needs to start over.
(If you are familiar with "conditional PUT" from HTTP, this is the same idea).
At a more advanced level, the requirement that the behavior of your system depends on the order that messages arrive is suspicious: see Udi Dahan's Race Conditions Don't Exist. Why is it wrong to change something after deleting it?
You might be interested in Martin Kleppmann's work on conflict resolution for eventual consistency. He specifically discusses examples where one writer edits an element that another writer deletes.
I've been using Spring Data for saving entities to the mongo DB and my code at the moment looks like this:
I have a repo class:
public interface LogRepo extends MongoRepository<Log, String> {
}
and I have an Entity Log which looks like this:
#Document(
collection = "logs"
)
public class Log {
#Id
private String id;
private String jsonMessage;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getJsonMessage() {
return jsonMessage;
}
public void setJsonMessage(String jsonMessage) {
this.jsonMessage = jsonMessage;
}
}
and this work well for me, however this approach works only for the case if I want to save Log entities to "logs" collection. However it would be very nice for me to be able to save Log entity to different collections depending on the context. I mean it would be nice to define collection name in the runtime. Is it possible somehow?
Thanks, cheers
Try to use inheritance and define appropriate collection names in such way. May give you possibility to save in different collections but you will be still not able to specify dynamically collection names and resp. their amount at runtime.
#Document(
collection = "logs"
)
public class Log {
#Id
private String id;
private String jsonMessage;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getJsonMessage() {
return jsonMessage;
}
public void setJsonMessage(String jsonMessage) {
this.jsonMessage = jsonMessage;
}
}
#Document(
collection = "log_child"
)
public class LogChild extends Log{}
With the MongoOperations save method you can choose which class to use and
based on the class it will choose the appropriate collection.
#Document(collection = "collection_#{T(com.github.your_project.DBUtils).getCollectionName()}")
public Class Collection
You can change the name in real time using a static getter
#UtilityClass
public class DBUtils {
private String collectionName;
public String getCollectionName() {
return collectionName;
}
public void setCollectionName(String collectionName) {
DBUtils.collectionName = collectionName;
}
}
Well i want to know if there is a much appropriate way to tackle generating auto id with string values, my first idea is creating an auto increment id which we can call auto_id then before saving a new entity I'll query for the latest data inside the db to get the id then I'll add 1 to my auto generate value column that I assign name which is stringValue+(id+1) though I'm concerned on how it will affect the performance as to saving this entity needs two access in db which is fetching and saving... like my question earlier is there a much appropriate way to handle this scenario?
And also sorry for my English guys if you want to clarify things with my question kindly ask, thnx in advance..
Here's my code for AttributeModel for hibernate annotation
#Component
#Entity
#Table(name="attribute_info")
public class AttributeModel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="attr_id", nullable=false, unique=true)
private int id;
#Column(name="attr_name")
private String name;
#Column(name="attr_desc")
private String desc;
#Column(name="attr_active")
private int active;
#Column(name="attr_abbr")
private String abbr;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="stats_id", referencedColumnName="stats_id")
private BaseStatisticModel baseStats;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getActive() {
return active;
}
public void setActive(int active) {
this.active = active;
}
public String getAbbr() {
return abbr;
}
public void setAbbr(String abbr) {
this.abbr = abbr;
}
public BaseStatisticModel getBaseStats() {
return baseStats;
}
public void setBaseStats(BaseStatisticModel baseStats) {
this.baseStats = baseStats;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
I can only say "Don't do it". How is a String ID like "str10001" better than 10001? It can't be an optimization as strings take more memory and more time. So I guess you need to pass it to some String-expecting method later.
If so, then pass "str" + id instead. Constructing the string on the fly surely won't saturate your server.
If not, then let us know what you actually need rather than what you think it could help you to achieve it.
I'm pretty sure, Hibernate can't do it. It couldn't some long time ago I checked it recently and it makes no sense (in any case, it's not a feature crowds would request).