I have an existing REST application which is caching a POJO (E.g Trade object) to ehcache and many other applications are using that. Some are sending that Trade object to REST service so that it can be persisted to Cache and DB and some are doing get operation on this cache using REST service.
public class Trade implements Serializable {
private static final long serialVersionUID = -92565215465632589L;
private String tradeNo = new String();
private String isin = new String();
private String quantity = new String();
.... //getters and setters
}
Now I want to add one more component to our application which uses many of the above trade attributes and many new also I want to add as a part of the functionality. I don't want to add new attributes to exist Trade POJO as it will impact existing code also. Shall I create new POJO which will extend Trade and add new attributes and persist this new POJO to cache? I will have almost similar object in cache with this approach :-( . any other good approach or design pattern is available?
public class ExtendedTrade extends Trade {
private String operation = new String();
private String dealType = new String();
private String identifier = new String();
.... //getters and setters
}
Above is the ExtendedTrade that I was describing in my approach.
Also please suggest any design so that I can avoid caching this similar type of object.
Embedding (maybe with delegate pattern) seems more solid under circumstances.
public class ExtendedTrade {
private Trade trade;
private String operation = "";
private String dealType = "";
private String identifier = "";
.... //getters and setters
}
Consider:
whether existing Trade can be extended to an ExtendedTrade (abstract).
whether an ExtendedTrade2 might come in existence, with other attributes.
whether you need to patch existing attributes of Trade.
I certainly won't insist that this is better.
Related
I'm trying to identify the best way to do mongodb object versioning.
Based on the mongodb document versioning pattern, storing revisions in a history collection and having current version in main collection is recommended. According to that, each revision contains the complete object instead of storing diffs.
Then I went through ways to implement data versioning in mongoDB where it recommends a method to store a single document containing all the revisions inside it having a separate history collection.
Therefore, I'm trying to implement my own object versioning implementation for the following document model due its complexity.
Invoice.java
public class Invoice {
private long invoiceId;
private String userName;
private String userId;
private LocalDateTime createdDate;
private LocalDateTime lastModifiedDate;
private List<String> operationalUnits;
private List<BodyModel> body;
private List<ReviewModel> reviews;
private BigDecimal changedPrice;
private String submitterId;
private LocalDateTime submittedTime;
private String approverId;
private LocalDateTime approvedTime;
}
BodyModel.java
public class BodyModel {
private String packageId;
private List<ItemModel> items;
private List<String> reviews;
}
ReviewModel.java
public class ReviewModel {
private String publishedTime;
private String authorName;
private String authorId;
private String text;
}
ItemModel.java
public class ItemModel {
private String itemNumber;
private String description;
private String brandId;
private String packId;
private List<String> reviews;
}
ER Diagram (Simplified)
At the moment, I'm using Javers library. But, Javers keeps the Invoice model as the main entity and other models such as BodyModel, ReviewModel, ItemModel as separated valueObjects. As a result, instead of creating a single revision document, it creates separated documents for the valueObjects. Additionally, it always constructs the current objects from the base version plus all changes which leads to huge read time. Addtionally, I identified a valueObjects issue that comes with javers. Refer this question for more info: MongoDB document version update issue with JaVers
Following are the issues, I've if I'm going to create my own implementation using spring boot.
If I'm going to put revisionId in each of the revisions (as shown in the below object) when mongoDB save(), how do I find the current revisionId to be included ?
{
_Id: <ObjectId>,
invoiceId: <InvoiceId>,
invoice: <Invoice>,
revisionId: <revisionId>
}
For this I can keep a field for revisionId in InvoiceModel which can be updated when saving to the main collection. And at the same time, it can be used to save the revision into history collection. Is it the best possible way to do it in this case ?
If I'm only going to store diffs, then how do I obtain the current version of the object ?
For this, it feels essential to fetch the current object from the main collection and then compare it with new version (I already have the new version, because that's what I'm going to store in main collection) to create the diff. Then diff can be stored in history collection and new version in main collection. Is it the best possible way to store diffs ?
In both scnearios, aspects coming from AOP can be used to intercept the save() method of the base repository to accomplish the task. But I don't mainly consider about coding implementation details, I would like to know which method or methods would be efficient in storing revisions for a data model such as given above (would like to discuss about methods I've mentioned as well) ?
TLDR;
Does my DailyRecordDataManager class have a code smell? Is it a 'God Class'? and how can I improve the structure?
Hi,
I'm working on my first project with Spring. It's going to fetch covid-19 data from the Madrid (where I live) government website, organise it by locality, and serve it up through an API.
Here is a sample of the JSON data I'm consuming.
{
"codigo_geometria": "079603",
"municipio_distrito": "Madrid-Retiro",
"tasa_incidencia_acumulada_ultimos_14dias": 23.4668991007149,
"tasa_incidencia_acumulada_total": 1417.23308497532,
"casos_confirmados_totales": 1691,
"casos_confirmados_ultimos_14dias": 28,
"fecha_informe": "2020/07/01 09:00:00"
}
Each JSON object is a a record of cases and the infection rate on a specific date and for a specific municipal district.
After fetching the data the program: parses it, filters it, trims/rounds some properties, maps it by locality, uses it to create an object for each locality (DistrictData), and writes the locality DistrictData objects to a MonoDB instance.
At the moment I have split each of these steps in the process separate classes, as per the single responsibility principle. As can be seen in the linked screenshot:
screenshot of intellij package structure
My problem is I don't know how to link these multiple classes together.
At the moment I have a Manager class which smells a bit like a God Class to me:
#Service
public class DailyRecordDataManager implements DataManager {
private final Logger logger = LoggerFactory.getLogger(DailyRecordDataManager.class);
private final DailyRecordDataCollector<String> dataCollector;
private final DataVerifier<String> dataVerifier;
private final JsonParser<DailyRecord> dataParser;
private final DataFilter<List<DailyRecord>> dataFilter;
private final DataTrimmer<List<DailyRecord>> dataTrimmer;
private final DataSorter<List<DailyRecord>> dataSorter;
private final DataMapper<List<DailyRecord>> dataMapper;
private final DataTransformer dataTransformer;
private final DistrictDataService districtDataService;
public DailyRecordDataManager(DailyRecordDataCollector<String> collector,
DataVerifier<String> verifier,
JsonParser<DailyRecord> parser,
DataFilter<List<DailyRecord>> dataFilter,
DataTrimmer<List<DailyRecord>> dataTrimmer,
DataSorter<List<DailyRecord>> dataSorter,
DataMapper dataMapper,
DataTransformer dataConverter,
DistrictDataService districtDataService) {
this.dataCollector = collector;
this.dataVerifier = verifier;
this.dataParser = parser;
this.dataFilter = dataFilter;
this.dataTrimmer = dataTrimmer;
this.dataSorter = dataSorter;
this.dataMapper = dataMapper;
this.dataTransformer = dataConverter;
this.districtDataService = districtDataService;
}
#Override
public boolean newData() {
String data = dataCollector.collectData();
if (!dataVerifier.verifyData(data)) {
logger.debug("Data is not new.");
return false;
}
List<DailyRecord> parsedData = dataParser.parse(data);
if (parsedData.size() == 0) {
return false;
}
List<DailyRecord> filteredData = dataFilter.filter(parsedData);
List<DailyRecord> trimmedData = dataTrimmer.trim(filteredData);
List<DailyRecord> sortedData = dataSorter.sort(trimmedData);
Map<String, List<DailyRecord>> mappedData = dataMapper.map(sortedData);
List<DistrictData> convertedData = dataTransformer.transform(mappedData);
districtDataService.save(convertedData);
return true;
}
}
I also thought about linking all of the involved classes together in a chain of Injected Dependencies -> so each class has the next class in the process as a dependency and, provided nothing goes wrong with the data, calls that next class in the chain when it's time.
I do also however feel that there must be a design pattern that solves the problem I have!
Thanks!
For anyone who finds this and wonders what I ended up opting for the Pipeline pattern.
It allowed me to easily organise all of the individual classes I was using into one clean workflow. It also made each stage of the process very easy to test. As well as the pipeline class itself!
I highly recommend anyone interested in the patter in Java to check out this article, which I used extensively.
I am new to Java and am using Java Eclipse, so please be kind! I hope I'm going to pose this question correctly so it makes sense.
I have four domains - each domain is pulling data from four different servers, hence the need to have them separate. But now I need to create a report that links all the data from the four domains into one report. Someone suggested using hashmaps, which I haven't used before. My four domains each have two fields that can be used as a key - CostCenter and Serial. The data being pulled is from machines all over the country. I need all the data for each machine in one report.
This is all being added to an existing project that creates a webpage with tabs for the user to click on for various tables and get data specific to a location, or to create a report for each page for all machines/locations. I just need to add a new link for the user to click on that will create this spreadsheet for them.
I've already created the domains (DAO, DAOImpl, DTO, and so on) and then I was going to create the combined report in my MainService.java. Here are the domains (lists) as declared in my MainService:
public List<Volume> getVolumeReport();
public List<BadFmPumps> getBadFmPumpsReport();
public List<BadCorobPumps> getBadCorobPumpsReport();
public List<McService> getMcServiceReport();
And here is data being pulled from the databases for each of them (domains):
public class Volume {
private String costCenter;
private String DAD;
private String division;
private String model;
private String serial;
private String numDispensers;
private String colorantSys;
private String CCEGals2017;
private String BACGals2017;
private String CCEGals2018;
private String BACGals2018;
private String DNR2017;
private String DNR2018;
private String DNR2019;
public class BadFmPumps {
private String costCenter;
private String model;
private String serial;
private String badFmPumps;
private String over10;
private String under10;
public class BadCorobPumps {
private String costCenter;
private String model;
private String serial;
private String badPumpCount;
public class McService {
private String costCenter;
private String model;
private String serial;
private String crChargeTotals;
private String emgCalls;
So I need to pull this data into one report wherever CostCenter + Serial matches. How do I declare the hashmaps for each object and how do I declare the key?
EDIT ----
I think I have something close here with
public List<Volume> getVolumeReport();
Map<String, Volume> VolumeMap = new HashMap<String, Volume>();
for (Volume dispenser : VolumeList)
{
String volumeKey = new StringBuilder().append(Volume.getCostCenter()).append(Volume.getSerial()).toString();
VolumeMap.put(volumeKey, dispenser);
}
Is this correct? I am getting one syntax error - the Map declaration
Map<String, Volume> VolumeMap = new HashMap<String, Volume>();
is giving me the error
Syntax error on token ";", { expected after this token
Is there something I need to change there?
There are some unusual things in your code. My guess is that you came from C# you are not using proper naming conventions see it here: https://www.oracle.com/technetwork/java/codeconventions-135099.html
You defined your method wrong, the error is not in the Map but the method definition
public List<Volume> getVolumeReport(); <-------- this
Should be
public List<Volume> getVolumeReport() {
And then close your method at its end (using }).
And inside your FOR you trying to direct access the Volume methods when you should use the variable you created: dispenser
String volumeKey = new StringBuilder()
.append(Volume.getCostCenter())
.append(Volume.getSerial())
.toString();
Should be
String volumeKey = new StringBuilder()
.append(dispenser.getCostCenter())
.append(dispenser.getSerial())
.toString();
I'm working on project where I need to create objects from different data sources/formats. I would like to know what is the best way to organize source code to make it easy.
Let's say I have class User and I want to have ability to create objects from data from database and JSON. The purpose of it is letting user of my app to browse data online and offline. I'm using GSON and ORMLite. In addition fields in JSON and database may be different, but the "main" fields are the same. Is it a good idea to create class which contains all properties/fields from JSON and database? Something similar to class below:
#DatabaseTable(tableName = "user", daoClass = UserDaoImpl.class)
public class User {
public static final String ID_FIELD_NAME = "id";
public static final String USER_LOGIN_FIELD_NAME = "login";
public static final String USER_EMAIL_FIELD_NAME = "email";
public static final String SERIALIZED_COUNTRY_FIELD_NAME = "user_county";
// DB & JSON
#DatabaseField(generatedId = true, columnName = ID_FIELD_NAME)
int id;
// DB & JSON
#DatabaseField(columnName = USER_LOGIN_FIELD_NAME)
String login;
//DB & JSON
#DatabaseField(columnName = USER_EMAIL_FIELD_NAME)
String email;
//Only JSON
#SerializedName(SERIALIZED_COUNTRY_FIELD_NAME)
String country;
public Track() {
}
}
Is it a good idea to create class which contains all properties/fields from JSON and database?
I think the short answer is yes. You can certain use the same objects to represent the data in the database and via JSON.
When you will get into problems is when you need to change the data representations in the database but don't want to change your JSON API or vice versa. Then you will need 2 separate classes and a mapping function between them.
But if you can get away with one class then that's the best way.
consider the factory pattern, you can use it to abstract the creation of concrete user classes as a function of the data source.
make User into an interface, and have a data-source specific implementation of User for each type of data source.
Which ORM supports a domain model of immutable types?
I would like to write classes like the following (or the Scala equivalent):
class A {
private final C c; //not mutable
A(B b) {
//init c
}
A doSomething(B b) {
// build a new A
}
}
The ORM has to initialized the object with the constructor. So it is possible to check invariants in the constructor. Default constructor and field/setter access to intialize is not sufficient and complicates the class' implementation.
Working with collections should be supported. If a collection is changed it should create a copy from the user perspective. (Rendering the old collection state stale. But user code can still work on (or at least read) it.) Much like the persistent data structures work.
Some words about the motivation. Suppose you have a FP-style domain object model. Now you want to persist this to a database. Who do you do that? You want to do as much as you can in a pure functional style until the evil sides effect come in. If your domain object model is not immutable you can for example not share the objects between threads. You have to copy, cache or use locks. So unless your ORM supports immutable types your constrainted in your choice of solution.
UPDATE: I created a project focused on solving this problem called JIRM:
https://github.com/agentgt/jirm
I just found this question after implementing my own using Spring JDBC and Jackson Object Mapper. Basically I just needed some bare minimum SQL <-> immutable object mapping.
In short I just use Springs RowMapper and Jackson's ObjectMapper to map Objects back and forth from the database. I use JPA annotations just for metadata (like column name etc...). If people are interested I will clean it up and put it on github (right now its only in my startup's private repo).
Here is a rough idea how it works here is an example bean (notice how all the fields are final):
//skip imports for brevity
public class TestBean {
#Id
private final String stringProp;
private final long longProp;
#Column(name="timets")
private final Calendar timeTS;
#JsonCreator
public TestBean(
#JsonProperty("stringProp") String stringProp,
#JsonProperty("longProp") long longProp,
#JsonProperty("timeTS") Calendar timeTS ) {
super();
this.stringProp = stringProp;
this.longProp = longProp;
this.timeTS = timeTS;
}
public String getStringProp() {
return stringProp;
}
public long getLongProp() {
return longProp;
}
public Calendar getTimeTS() {
return timeTS;
}
}
Here what the RowMapper looks like (notice it mainly delegats to Springs ColumnMapRowMapper and then uses Jackson's objectmapper):
public class SqlObjectRowMapper<T> implements RowMapper<T> {
private final SqlObjectDefinition<T> definition;
private final ColumnMapRowMapper mapRowMapper;
private final ObjectMapper objectMapper;
public SqlObjectRowMapper(SqlObjectDefinition<T> definition, ObjectMapper objectMapper) {
super();
this.definition = definition;
this.mapRowMapper = new SqlObjectMapRowMapper(definition);
this.objectMapper = objectMapper;
}
public SqlObjectRowMapper(Class<T> k) {
this(SqlObjectDefinition.fromClass(k), new ObjectMapper());
}
#Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
Map<String, Object> m = mapRowMapper.mapRow(rs, rowNum);
return objectMapper.convertValue(m, definition.getObjectType());
}
}
Now I just took Spring JDBCTemplate and gave it a fluent wrapper. Here are some examples:
#Before
public void setUp() throws Exception {
dao = new SqlObjectDao<TestBean>(new JdbcTemplate(ds), TestBean.class);
}
#Test
public void testAll() throws Exception {
TestBean t = new TestBean(IdUtils.generateRandomUUIDString(), 2L, Calendar.getInstance());
dao.insert(t);
List<TestBean> list = dao.queryForListByFilter("stringProp", "hello");
List<TestBean> otherList = dao.select().where("stringProp", "hello").forList();
assertEquals(list, otherList);
long count = dao.select().forCount();
assertTrue(count > 0);
TestBean newT = new TestBean(t.getStringProp(), 50, Calendar.getInstance());
dao.update(newT);
TestBean reloaded = dao.reload(newT);
assertTrue(reloaded != newT);
assertTrue(reloaded.getStringProp().equals(newT.getStringProp()));
assertNotNull(list);
}
#Test
public void testAdding() throws Exception {
//This will do a UPDATE test_bean SET longProp = longProp + 100
int i = dao.update().add("longProp", 100).update();
assertTrue(i > 0);
}
#Test
public void testRowMapper() throws Exception {
List<Crap> craps = dao.query("select string_prop as name from test_bean limit ?", Crap.class, 2);
System.out.println(craps.get(0).getName());
craps = dao.query("select string_prop as name from test_bean limit ?")
.with(2)
.forList(Crap.class);
Crap c = dao.query("select string_prop as name from test_bean limit ?")
.with(1)
.forObject(Crap.class);
Optional<Crap> absent
= dao.query("select string_prop as name from test_bean where string_prop = ? limit ?")
.with("never")
.with(1)
.forOptional(Crap.class);
assertTrue(! absent.isPresent());
}
public static class Crap {
private final String name;
#JsonCreator
public Crap(#JsonProperty ("name") String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
}
Notice in the above how easy it is to map any query into immutable POJO's. That is you don't need it 1-to-1 of entity to table. Also notice the use of Guava's optionals (last query.. scroll down). I really hate how ORM's either throw exceptions or return null.
Let me know if you like it and I'll spend the time putting it on github (only teste with postgresql). Otherwise with the info above you can easily implement your own using Spring JDBC. I'm starting to really dig it because immutable objects are easier to understand and think about.
Hibernate has the #Immutable annotation.
And here is a guide.
Though not a real ORM, MyBatis may able to do this. I didn't try it though.
http://mybatis.org/java.html
AFAIK, there are no ORMs for .NET supporting this feature exactly as you wish. But you can take a look at BLTookit and LINQ to SQL - both provide update-by-comparison semantics and always return new objects on materialization. That's nearly what you need, but I'm not sure about collections there.
Btw, why you need this feature? I'm aware about pure functional languages & benefits of purely imutable objects (e.g. complete thread safety). But in case with ORM all the things you do with such objects are finally transformed to a sequence of SQL commands anyway. So I admit the benefits of using such objects are vaporous here.
You can do this with Ebean and OpenJPA (and I think you can do this with Hibernate but not sure). The ORM (Ebean/OpenJPA) will generate a default constructor (assuming the bean doesn't have one) and actually set the values of the 'final' fields. This sounds a bit odd but final fields are not always strictly final per say.
SORM is a new Scala ORM which does exactly what you want. The code below will explain it better than any words:
// Declare a model:
case class Artist ( name : String, genres : Set[Genre] )
case class Genre ( name : String )
// Initialize SORM, automatically generating schema:
import sorm._
object Db extends Instance (
entities = Set() + Entity[Artist]() + Entity[Genre](),
url = "jdbc:h2:mem:test"
)
// Store values in the db:
val metal = Db.save( Genre("Metal") )
val rock = Db.save( Genre("Rock") )
Db.save( Artist("Metallica", Set() + metal + rock) )
Db.save( Artist("Dire Straits", Set() + rock) )
// Retrieve values from the db:
val metallica = Db.query[Artist].whereEqual("name", "Metallica").fetchOne() // Option[Artist]
val rockArtists = Db.query[Artist].whereEqual("genres.name", "Rock").fetch() // Stream[Artist]