I am working with a technology called Verastream Host Integrator. Essentially VHI is a no-code/low-code GUI tool for working with mainframe data that that compiles into Java bindings.
One of the issues with VHI is that it can only output flat data. Here is an example:
public class VhiProcedureRecord {
private String foo1;
private String foo2;
private String bar1;
private String bar2;
// constructors, getters, and setters
}
I am piping this output through a Spring Boot middleware layer and I want to remap this object into something that would look like this:
public class Foo {
private String foo1;
private String foo2;
// constructors, getters, and setters
}
public class Bar {
private String bar1;
private String bar2;
// constructors, getters, and setters
}
public class MyRecord {
private Foo foo;
private Bar bar;
// constructors, getters, and setters
}
As you can see this requires splitting the fields in VhiProcedureRecord between Foo and Bar.
Doing this manually quickly becomes a huge pain.
The other problem with the output being flat is when the VHI output contains a list of data, it returns multiple records with duplicate fields, akin to what a SQL join would look like e.g.
public class VhiPetOwnershipRecord {
private String ownerName;
private String petName;
// constructors, getters, and setters
}
The result of this procedure returns something akin to:
[
{"ownerName": "JHuang", "petName": "Fido"},
{"ownerName": "JHuang", "petName": "Spot"}
]
And I want to remap this into:
public class MyPetOwnershipRecord {
private String ownerName;
private List<String> petName;
}
Is there a way to use Jackson or something similar to do this sort of remapping automatically?
Keep in mind that VhiProcedureRecord is compiled by VHI, so that class can't be changed.
Related
I have a Spring Application which is built on top of DynamoDB. I am trying to write a saveFoo() Repository method that will save an object of type Foo to the database. This method will be called from the application layer.
What I'm struggling with is that the Foo class has fields within it that are Dynamo specific. I don't want clients of the saveFoo() class to think they need to create an object of type Foo with these fields. Nor do I want them to attempt to ever set these values themselves.
These database-specific fields need public getters and setters in order to work with the DynamoDB SDK.
The database model class looks like the following:
#DynamoDBTable(tableName = "foo")
public class Foo {
// Fields the client should be setting
private String bar;
private String baz;
// Fields the client should not access and should not care about. They are internal fields used for DynamoDB purposes.
private Long version;
private String gsiIndexKey;
// Empty constructor needed for deserialization of data from dynamodb
public Foo() {
}
// Getters and setters for all of the above fields.
}
And the repository method to save the object to the DB:
public class FooRepositoryImpl {
public Foo saveFoo(WhatClassShouldThisBe foo) {
// Code that saves a new Foo item to the database and returns it.
}
}
My current idea is to create a FooWrapper interface that the saveFoo() method can take as a parameter. The wrapper will allow the client to set the fields that they should have control over, but does not expose fields related to the database internals. Something like the below:
/**
* Allows us restrict visibility of the Foo fields to the Application by hiding database internal fields.
**/
public interface FooWrapper {
Foo getFoo()
}
public class FooWrapperImpl implements FooWrapper {
private final Foo foo;
public FooWrapperImpl(String bar, String baz) {
foo = new Foo();
foo.setBar(bar);
foo.setBaz(baz);
}
#Override
public Foo getFoo() {
return foo;
}
}
public class FooRepositoryImpl {
public Foo saveFoo(FooWrapper fooWrapper) {
Foo foo = fooWrapper.getFoo(); // Save this item to db
// Code that saves a new Foo item to the database and returns it.
}
}
What are your thoughts on this approach? Does anyone know of some better techniques I could try? I can't help but feel that I am over-engineering things here.
Expose only an interface to clients that has the methods you want. Internally you can call the other public methods of the implementation, but the client code won't know them.
If you are using modern Java, don't export your implementation classes outside of your module. Only export the public interface.
You could also keep an interface for internal use that has more methods than the public API.
public interface Foo {
public void setBar(String bar);
public void setBaz(String baz);
}
#DynamoDBTable(tableName = "foo")
public class FooImpl implements Foo {
// Fields the client should be setting
private String bar;
private String baz;
// Fields the client should not access and should not care about. They are internal fields used for DynamoDB purposes.
private Long version;
private String gsiIndexKey;
// Empty constructor needed for deserialization of data from dynamodb
public FooImpl() {
}
// Getters and setters for all of the above fields.
#Override
public void setBar(String bar) {
this.bar = bar;
}
#Override
public void setBaz(String baz) {
this.baz = bar;
}
// Not part of the Foo interface
public void setVersion(Long version) {
this.version = version;
}
public void setGsiIndexKey(String indexKey) {
this.gsiIndexKey = indexKey;
}
}
So I am aware that Spring automatically maps complex objects correctly when provided like:
#PostMapping("/foo")
public String insertObject(#ModelAttribute MyComplexObject bar) {
//do something
return "redirect:baz";
}
given that MyComplexObject has "mappable" attributes, for instance something similar to:
public class MyComplexObject {
private long id;
private String name;
public MyComplexObject(long id, String name) {
this.id = id;
this.name = name;
}
// setters & getters etc
}
However, what if the required object in turn has other complex objects as attributes, e.g. MyComplexObject keeps a list of MyOtherObject which again could reference another one and so on.
A possible solution I found was creating a form object for the required class which translates all attributes to mappable types, but even then it'd be rather tedious and messy depending on complexity.
Every suggestion is much appreciated!
I have some BaseX pojo class ex:
public class Base1 {
private String base1Field1;
private String base1Field2;
// getter & setter
}
public class Base2 {
private String base2Field1;
private String base2Field2;
// getter & setter
}
And some DomainVo pojo class, it has some field & method from BaseX class ex:
//from base1
public class Domain1Vo {
private String domain1Field1;
private String base1Field1;
private String base1Field2;
// getter & setter
}
//from base1 & base 2
public class Domain2Vo {
private String domain2Field1;
private String base1Field1;
private String base1Field2;
private String base2Field1;
private String base2Field2;
// getter & setter
}
I don't want copy paste those fields from BaseX class to my domain object, but I can't use extends Base1, Base2 because java don't allow it.
I don't actually use BaseX in my code, I define them just want a single place to maintain those field.
update:
I can't change my domain object structure, because it's come from/to other service as json. Also I need use it to generate a swagger doc(I use springfox). This why I need both field & method.
======== some research I did
I found a lib called lombok, it has a feature name #Delegate
https://projectlombok.org/features/experimental/Delegate
//from base1
public class Domain1Vo {
private String domain1Field1;
#Delegate
private Base1 base1;
// getter & setter
}
It can generate method from BaseX class, but not field.
Composition is what you want. Inheritance is wildly overused (also getters and, especially, setters).
The base classes become components. (Use better names! Even "base" isn't a useful word to use in a class name.)
public final class Component1 {
private String component1Field1;
private String component1Field2;
// domain methods
}
public final class Component2 {
private String component2Field1;
private String component2Field2;
}
public final class Domain1Vo {
private String domain1Field1;
private final Component1 component1;
public Domain1Vo(
Component1 component1
) {
// Or construct.
this.component1 =
Objects.requireNonNull(component1);
}
// domain methods
}
//from base1 & base 2
public final class Domain2Vo {
private String domain2Field1;
private final Component1 component1;
private final Component2 component2;
public Domain2Vo(
Component1 component1,
Component2 component2,
) {
// Or construct.
this.component1 =
Objects.requireNonNull(component1);
this.component2 =
Objects.requireNonNull(component2);
}
// domain methods
}
i have a model like this
public class WorkDB extends RealmObject {
private String address;
private RealmList<ReportDB> reports;
getters setters
}
public class ReportDB extends RealmObject implements Serializable{
private int idReport;
private String nameReport;
private RealmList<ReplieGroupDB> repliesGroup;
private RealmList<QuestionGroupDB> questionGroups;
getters setters
}
public class QuestionGroupDB extends RealmObject {
private int idQuestionGroupInReplie;
private String nameQuestionGroupInReplie;
private RealmList<QuestionDB> questions;
private int times;
}
How can i do a query like
realm.search(WorkDb.class).where(id,20).and(ReportDb.class).where(idReport,1).and(QuestionGroupDB.class).where(idQuestionGroupInReplie,2);
To avoid do a query to get WorkDB and do a for each in reports to find by id, and then, other do a other for each in questionGroupsDB to find any by id..
If you want to retrieve a list QuestionDB objects there is unfortunately no other way around it than building a manual query like the one you describe. We have a concept called BackLinks on our TODO (https://github.com/realm/realm-java/issues/607) which would make it possible to do the sort of query you are looking for, but currently you will have to do it manually. Sorry.
This is not the first time that I've found myself in a situation in which I have to adapt two objects with almost the same data, for example:
User.java (Object returned from another library)
private String name;
private String surname;
private String email;
private String telephone;
...
getters and setters();
constructor();
MyUser.java
private String name;
private String surname;
private String email;
private String telephone;
...
getters and setters();
constructor();
I usually create a method to convert one object into another one, like this:
User m1 = new User();
MyUser m2 = new MyUser();
m2.setName(m1.getName());
m2.setsurmame(m1.getsurname());
...and so on...
Does anybody know a different way to do this kind of stuff?
Use Object Composition For objects that you create using the other library, create an instance of ExternalUser. But if you want to create them locally, create a BrandNewUser. Then you can just treat them the same way, with one version using the pass-through composition methods, and the ones created by your code using your own internal implementation.
You can create your object like this:
public interface MyUser {
// all the methods you need
String getSurname();
}
public class ExternalUser implements MyUser {
private User _user;
private ExternalUser() { }
public ExternalUser(User u) {
this._user = u;
}
public String getSurname() {
return _user.getSurname();
}
}
public class BrandNewUser implements MyUser {
private String _surname;
public ExternalUser(String name, String surname) {
this._surname = surname;
}
public String getSurname() {
return _surname;
}
}
There is a AutoMapper project in C Sharp.
In the gist of it it provides an easy way of mapping properties from a source instance to a destination instance where the source and destination instances can be of different classes.
this link shares some interesting thoughts about similar projects in Java : Automapper for Java
One thing you can do is pass that User object in a method of MyUser class or constructor of MyUser class and then perform those setters.
Using constructor :
public MyUser(User u){
setName(u.getName());
setSurname(u.getSurname());
...
}
Or creating a seperate method :
public void setMyUser(User u){
setName(u.getName());
setSurname(u.getSurname());
...
}
Then you can use it like this:
User u = new User();
//hope all values are set in User u object
MyUser m = new MyUser(u);
In cases where appropriate, refactor those objects to inherit from each other, rather than duplicate properties and logic.
In cases where the objects must remain distint, you can use any one of a variety of clone tools to perform deep copies from object to object. Here is a decent, non-exhaustive list:
Orika
Dozer
PropertyUtils
Maybe you can use beanutils which provides copy properties function.
http://commons.apache.org/beanutils/