I'm using java-object-diff to get differences between two objects parsed from xml by JAXB. In below example, I'm using the same string to test if I get no differences, however log.info("has changes: " + diff5.hasChanges()); logs true.
JAXBContext context1 = JAXBContext.newInstance(Item.class);
Unmarshaller m1 = context1.createUnmarshaller();
Item base = (Item) m1.unmarshal(new StringReader(s));
Item working = (Item) m1.unmarshal(new StringReader(s));
DiffNode diff5 = ObjectDifferBuilder
.buildDefault()
.compare(working, base);
log.info("has changes: " + diff5.hasChanges());
diff5.visit((node, visit) -> {
final Object baseValue = node.canonicalGet(base);
final Object workingValue = node.canonicalGet(working);
final String message = node.getPath() + " changed from " +
baseValue + " to " + workingValue;
System.out.println(message);
});
The message I get from System.out.println is always the same, saying it has changed from null to <the actual value> This happens for every property. E.g.
content changed from null to Mit dem Wasserinonisator
I have verified that the both Items have the same content and none of the both actualy is not null, but the exact same content.
Item is a pojo with many subclasses (all getters and setters are present), e.g.
public class Item {
#XmlElement(name = "ASIN", required = true)
protected String asin;
#XmlElement(name = "ParentASIN")
protected String parentASIN;
#XmlElement(name = "Errors")
protected Errors errors;
#XmlElement(name = "DetailPageURL")
protected String detailPageURL;
#XmlElement(name = "ItemLinks")
protected ItemLinks itemLinks;
#XmlElement(name = "SalesRank")
protected String salesRank;
#XmlElement(name = "SmallImage")
protected Image smallImage;
}
Is there any way to make java-object-diff work, to make it compare the values correctly?
After taking a closer look at your code I know what's wrong. The first problem is the fact, that JAXB doesn't generate equals methods. For the most part, that's not a problem, because the ObjectDiffer can establish the relationship between objects based on the hierarchy. Things get more complicated when ordered or unordered Collections are involved, because the ObjectDiffer needs some kind of way to establish the relationship between the collection items in the base and working instance. By default it relies on the lookup mechanism of the underlying collection (which typically involves on or more of the methods hashCode, equals or compareTo.)
In your case this relationship cannot be established, because none of your classes (but especially those contained in Lists and Sets) implement a proper equals method. This means that instances are only ever equal to themselves. This is further complicated by the fact, that the responsible classes represent value objects and don't have any hard identifier, that could be used to easily establish the relationship. Therefore the only option is to provide custom equals methods that simply compare all properties. The consequence is, that the slightest change on those objects will cause the ObjectDiffer to mark the base version as REMOVED and the working version as ADDED. But it will also not mark them as CHANGED, when they haven't actually changed. So that's something.
I'm not sure how easy it is to make JAXB generate custom equals methods, so here are some alternative solutions possible with java-object-diff:
Implement your own de.danielbechler.diff.identity.IdentityStrategy for the problematic types and provide them to the ObjectDifferBuilder, like so (example uses Java 8 Lambdas):
ObjectDifferBuilder
.startBuilding()
.identity()
.ofCollectionItems(ItemLinks.class, "itemLink").via((working, base) -> {
ItemLink workingItemLink = (ItemLink) working;
ItemLink baseItemLink = (ItemLink) base;
return StringUtils.equals(workingItemLink.getDescription(), baseItemLink.getDescription())
&& StringUtils.equals(workingItemLink.getURL(), baseItemLink.getURL());
})
// ...
.and().build();
Ignore problematic properties during comparison. Obviously this may not be what you want, but it's an easy solution in case you don't really care about the specific object.
ObjectDifferBuilder
.startBuilding()
.inclusion()
.exclude().type(Item.ImageSets.class)
.and().build();
A solution that causes JAXB to generate custom equals methods would be my preferred way to go. I found another post that claims it's possible, so maybe you want to give this a try first, so you don't have to customize your ObjectDiffer.
I hope this helps!
Related
Say I use Open CSV and have something like:
public class MyDto {
#CsvBindByName(column = "AFBP")
String placeholderA;
#CsvBindByNames({
#CsvBindByName(column = "ABCD"),
#CsvBindByName(column = "AFEL")
})
String placeholderB;
#CsvBindByNames({
#CsvBindByName(column = "ABCD"),
#CsvBindByName(column = "ALTM")
})
String placeholderC;
#Override
public String toString() {
return "placeholder A = " + placeholderA + ", placeholderB = " + placeholderB + ", placeholderC = " + placeholderC;
}
}
After deserializing
var csv = "AFBP,ABCD\nthis is A,this is B and C";
I got
placeholder A = this is A, placeholderB = null, placeholderC = this is B and C
rather than what I need:
placeholder A = this is A, placeholderB = this is B and C, placeholderC = this is B and C
Question
Is there a way, using this library or similar (providing support for annotations), to deserialize the CSV that a one-column-to-many-fields mapping is possible?
No, this is not possible, at least with OpenCSV version 5.7.1. Yet, this might change with future releases.
The reason originates from the way how OpenCSV registers a Beans/Pojos field to column mappings via the HeaderColumnNameMappingStrategy. This is used by default for CsvToBeanBuilder:
This builder is intelligent enough to guess the mapping strategy according to the following strategy:
If a mapping strategy is explicitly set, it is always used.
If CsvBindByPosition or CsvCustomBindByPosition is present, ColumnPositionMappingStrategy is used.
Otherwise, HeaderColumnNameMappingStrategy is used. This includes the case when CsvBindByName or CsvCustomBindByName are being used. The
annotations will automatically be recognized.
Internally, the class HeaderColumnNameMappingStrategy will call registerBinding(..). In this context, the columnName of a Pojo (here: MyPojo) is used as a key for the mapping info in fieldMap.
Sadly, the current implementation does not check, in line 168, if a mapping is already present for a key (eg, ABCD). Thus, it will overwrite the first bound field placeholderB with a new binding for placeholderC. As a result, the parsing will only recognize that it should map values from the csv input to the field placeholderC, as you observed.
Side node: I tested your code and can confirm the output as given in your question.
The only idea that comes to my mind:
Write your own implementation of a headers (to) column name strategy.
Start by extending from HeaderNameBaseMappingStrategy. This way you could handle existing field-to-column mappings for multiple occurrences correctly.
Obviously, you need to register your custom, or multi-field strategy with the CsvToBeanBuilder#withMappingStrategy(..) method.
More consequently, you could open a change request to support the desired behavior. This way, the existing mapping strategy could be improved to cope with such a requirement brought up by your question here.
Currently, no other options seem to exist.
I have the following in a working test:
when(client.callApi(anyString(), isA(Office.class))).thenReturn(responseOne);
Note that client is a Mock of class Client.
I want to change "isA(Office.class)" to tell it to match where the "id" property of an Office instance is "123L". How can I specify that I want a specific argument value in the method of a mocked object?
Edit: Not a duplicate because I'm trying to use it on a "when" and the linked question (and other resources I've found) are using ArgumentCaptor and ArgumentMatcher on "verify" and "assert". I'm thinking I can't actually do what I'm trying and will try out another way. Of course, I'm willing to be shown otherwise.
Reopening as requested, but the solution (use an ArgumentMatcher) is identical to the one in the linked answer. Naturally, you can't use an ArgumentCaptor when stubbing, but everything else is the same.
class OfficeWithId implements ArgumentMatcher<Office> {
long id;
OfficeWithId(long id) {
this.id = id;
}
#Override public boolean matches(Office office) {
return office.id == id;
}
#Override public String toString() {
return "[Office with id " + id + "]";
}
}
when(client.callApi(anyString(), argThat(new IsOfficeWithId(123L)))
.thenReturn(responseOne);
Because ArgumentMatcher has a single method, you can even make it a lambda in Java 8:
when(client.callApi(anyString(), argThat(office -> office.id == 123L))
.thenReturn(responseOne);
If you're already using Hamcrest, you can adapt a Hamcrest matcher using MockitoHamcrest.argThat, or use the built-in hasProperty:
when(client.callApi(
anyString(),
MockitoHamcrest.argThat(
hasProperty("id", equalTo(123L)))))
.thenReturn(responseOne);
I ended up going with "eq". This was ok in this case because the objects are pretty simple. First I created an object that is the same as what I expect to get back.
Office officeExpected = new Office();
officeExpected.setId(22L);
Then my 'when' statement becomes:
when(client.callApi(anyString(), eq(officeExpected))).thenReturn(responseOne);
This allows me to have better checking than "isA(Office.class)".
adding an answer for anyone with a more complex object.
answer from OP uses eq which works for simple objects.
However, I had a more complex object with many more fields. Its quite painful to create Mock object and fill in all the fields
public class CreateTenantRequest {
#NotBlank private String id;
#NotBlank private String a;
#NotBlank private String b;
...
...
}
I was able to use refEq to achieve the same thing without setting a value of each field.
Office officeExpected = new Office();
officeExpected.setId(22L);
verify(demoMock, Mockito.atLeastOnce()).foobarMethod(refEq(officeExpected, "a", "b"));
I have a class which is used to get transfer data from the one application to another and then also to update if changes were made.
public class Data {
private String name;
private String number;
private String info;
... getters/setters...
}
Let's say name and number will be updated if you change them but e.g. info is not. What's the best way to tell programmers in the future that this is intended so they can recognize it immediately?
Update:
It's encoded as a JSON file and when I get it back I don't care about the info field anymore. It could be empty
You can create your custom annotation, specific to your application. If you are using any framework like Hibernate you can use #transient.
Probably not the correct way, but if you are just talking about "informing" other programmers, you could simply put the transient keyword on your info field.
But of course, that would be really "informal"; as it would probably not at all affect how your framework is dealing with your fields.
I would use serialisation combined with the transient keyword
What is object serialization?
import java.io.*;
import java.util.*;
// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {
// These attributes conform the "value" of the object.
// These two will be serialized;
private String aString = "The value of that string";
private int someInteger = 0;
// But this won't since it is marked as transient.
private transient List<File> unInterestingLongLongList;
There's no indication in your file that name or number are being persisted.
If you are going to put behavior into the file in some durable way, this isn't just a file, it's a representation of an object, where data and the related behavior live as one. Write a method clarifying the intent.
public boolean isStorable() {
boolean isOk = true;
isOk &= (name != null && name.length() > 0);
isOk &= (number > 0);
return isOk;
}
Makes it clear that not every one of these items contribute to being able to store the object, and that not every value within these items contribute to a valid storage state.
It also makes it clear that this object permits invalid states within its private data. That's a code smell that could indicate a design flaw. Perhaps you should look into whether that is a design flaw, and if it is, then fix it.
Start here https://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html
Almost any programmer seing a POJO like this will know that behaviour is what you explained....
#Table(name = "data")
public class Data {
#Id
#Column(name = "name")
private String name;
#Column(name = "number")
private String number;
private String info;
... getters/setters...
}
UPDATE: It's encoded as a JSON file and when I get it back I don't care about the info field anymore. It could be empty
In my application, I have to instantiate many different types of objects. Each type contains some fields and needs to be added to a containing type. How can I do this in an elegant way?
My current initialization step looks something like this:
public void testRequest() {
//All these below used classes are generated classes from xsd schema file.
CheckRequest checkRequest = new CheckRequest();
Offers offers = new Offers();
Offer offer = new Offer();
HotelOnly hotelOnly = new HotelOnly();
Hotel hotel = new Hotel();
Hotels hotels = new Hotels();
Touroperator touroperator = new Touroperator();
Provider provider = new Provider();
Rooms rooms = new Rooms();
Room room = new Room();
PersonAssignments personAssignments = new PersonAssignments();
PersonAssignment personAssignment = new PersonAssignment();
Persons persons = new Persons();
Person person = new Person();
Amounts amounts = new Amounts();
offers.getOffer().add(offer);
offer.setHotelOnly(hotelOnly);
room.setRoomCode("roomcode");
rooms.getRoom().add(room);
hotels.getHotel().add(hotel);
hotel.setRooms(rooms);
hotelOnly.setHotels(hotels);
checkRequest.setOffers(offers);
// ...and so on and so on
}
I really want to avoid writing code like this, because it's a little messy having to instantiate each object separately and then initialize each field across multiple lines of code (e.g. having to call new Offer() and then setHotelOnly(hotelOnly) and then add(offer)).
What elegant methods can I use instead of what I have? Are there any "Factories" that can be used? Do you have any references/examples to avoid writing code like this?
I'm really interested in implementing clean code.
Context:
I'm developing a RestClient Application for sending post requests to a Webservice.
The API is represented as a xsd schema file and I created all the Objects with JAXB
Before sending a request I have to instantiate many Objects because they have dependencies with each other.
(An Offer has Hotels, a Hotel has Rooms, a Room has Persons... And these Classes are the generated ones)
Thanks for your help.
You can either use a constructor or a builder pattern or a variation of the builder pattern to fix the problem of having too many fields in your initialization step.
I'm going to extend your example a bit to prove my point of why these options are useful.
Understanding your example:
Lets say an Offer is simply a container class for 4 fields:
public class Offer {
private int price;
private Date dateOfOffer;
private double duration;
private HotelOnly hotelOnly;
// etc. for as many or as few fields as you need
public int getPrice() {
return price;
}
public Date getDateOfOffer() {
return dateOfOffer;
}
// etc.
}
As it stands in your example, to set values to these fields, you use setters:
public void setHotelOnly(HotelOnly hotelOnly) {
this.hotelOnly = hotelOnly;
}
Unfortunately, this means if you need an offer with values in all of the fields, you have to do what you have:
Offers offers = new Offers();
Offer offer = new Offer();
offer.setPrice(price);
offer.setDateOfOffer(date);
offer.setDuration(duration);
offer.setHotelOnly(hotelOnly);
offers.add(offer);
Now let's look at improving this.
Option 1: Constructors!
A constructor other than the default constructor (the default constructor is currently Offer() ) is useful for initializing the values of the fields in your class.
A version of Offer using constructors would look like this:
public class Offer {
private int price;
private Date dateOfOffer;
//etc.
// CONSTRUCTOR
public Offer(int price, Date dateOfOffer, double duration, HotelOnly hotelOnly) {
this.price = price;
this.dateOfOffer = dateOfOffer;
//etc.
}
// Your getters and/or setters
}
Now, we can initialize it in one line!
Offers offers = new Offers();
Offer offer = new Offer(price, date, duration, hotelOnly);
offers.add(offer);
Even better, if you never use offer other than that single line: offers.add(offer); you don't even need to save it in a variable!
Offers offers = new Offers();
offers.add( new Offer(price, date, duration, hotelOnly) ); // Works the same as above
Option 2: Builder Pattern
A builder pattern is useful if you want the option of having default values for any of your fields.
The problem a builder pattern solves is the following messy code:
public class Offer {
private int price;
private Date dateOfOffer;
// etc.
// The original constructor. Sets all the fields to the specified values
public Offer(int price, Date dateOfOffer, double duration, HotelOnly hotelOnly) {
this.price = price;
this.dateOfOffer = dateOfOffer;
// etc.
}
// A constructor that uses default values for all of the fields
public Offer() {
// Calls the top constructor with default values
this(100, new Date("10-13-2015"), 14.5, new HotelOnly());
}
// A constructor that uses default values for all of the fields except price
public Offer(int price) {
// Calls the top constructor with default values, except price
this(price, new Date("10-13-2015"), 14.5, new HotelOnly());
}
// A constructor that uses default values for all of the fields except Date and HotelOnly
public Offer(Date date, HotelOnly hotelOnly) {
this(100, date, 14.5, hotelOnly);
}
// A bunch more constructors of different combinations of default and specified values
}
See how messy that can get?
The builder pattern is another class that you put inside your class.
public class Offer {
private int price;
// etc.
public Offer(int price, ...) {
// Same from above
}
public static class OfferBuilder {
private int buildPrice = 100;
private Date buildDate = new Date("10-13-2015");
// etc. Initialize all these new "build" fields with default values
public OfferBuilder setPrice(int price) {
// Overrides the default value
this.buildPrice = price;
// Why this is here will become evident later
return this;
}
public OfferBuilder setDateOfOffer(Date date) {
this.buildDate = date;
return this;
}
// etc. for each field
public Offer build() {
// Builds an offer with whatever values are stored
return new Offer(price, date, duration, hotelOnly);
}
}
}
Now, you can not have to have so many constructors, but still are able to choose which values you want to leave default, and which you want to initialize.
Offers offers = new Offers();
offers.add(new OfferBuilder().setPrice(20).setHotelOnly(hotelOnly).build());
offers.add(new OfferBuilder().setDuration(14.5).setDate(new Date("10-14-2015")).setPrice(200).build());
offers.add(new OfferBuilder().build());
That last offer is simply one with all default values. The others are default values except the ones that I set.
See how that makes things easier?
Option 3: Variation of Builder Pattern
You can also use the builder pattern by simply making your current setters return the same Offer object. It's exactly the same, except without the extra OfferBuilder class.
Warning: As user WW states below, this option breaks JavaBeans - a standard programming convention for container classes such as Offer. So, you shouldn't use this for professional purposes, and should limit your use in your own practices.
public class Offer {
private int price = 100;
private Date date = new Date("10-13-2015");
// etc. Initialize with default values
// Don't make any constructors
// Have a getter for each field
public int getPrice() {
return price;
}
// Make your setters return the same object
public Offer setPrice(int price) {
// The same structure as in the builder class
this.price = price;
return this;
}
// etc. for each field
// No need for OfferBuilder class or build() method
}
And your new initialization code is
Offers offers = new Offers();
offers.add(new Offer().setPrice(20).setHotelOnly(hotelOnly));
offers.add(new Offer().setDuration(14.5).setDate(new Date("10-14-2015")).setPrice(200));
offers.add(new Offer());
That last offer is simply one with all default values. The others are default values except the ones that I set.
So, while it's a lot of work, if you want to clean up your initialization step, you need to use one of these options for each of your classes that have fields in them. Then use the initialization methods that I included with each method.
Good luck! Does any of this need further explanation?
I've always preferred using builder-pattern-with-a-twist because it provides much more than the basic approach of the builder pattern.
But what happens when you want to tell the user that she must call one builder method or the other, since it is crucial for the class you’re trying to build.
Think about a builder for a URL component. How would one think about the builder methods for encapsulating access to URL attributes, are they equally important, do they interact with each other, etc? While the query parameters or fragment are optional the hostname is not; you could say that protocol is also required but for that you can have a meaningful default, like http right?
Anyway, I don't know if this makes sense to your particular problem but I thought it would be worth mentioning for others to have a look at it.
Some nice answeres are already given here!
What came to my mind as an addition is Domain Driven Design. Specific the Building blocks part, with Entity, Value Object, Aggregate, Factory etc.
A nice introduction is given in Domain Driven Design - Quickly (pdf).
I just provide this answer because it was mentioned in a comment and I think it should also be a part of this enumeration of Design Patterns.
Null Object Design Pattern
Intent
The intent of a Null Object is to encapsulate the absence of an object by providing a substitutable alternative that offers suitable default do nothing behavior. In short, a design where "nothing will come of nothing"
Use the Null Object pattern when
an object requires a collaborator. The Null Object pattern does not introduce this collaboration--it makes use of a collaboration that already exists
some collaborator instances should do nothing
you want to abstract the handling of null away from the client
Here you find the full part of "Null Object" Design Pattern
Ideally, an object should not be concerned about instantiating its dependencies. It should only worry about things that it is supposed to do with them.
Have you considered any dependency injection framework? Spring or Google's Juice are quite versatile and have a small footprint.
The idea is simple, you declare the dependencies and let the framework decide when/how/where to create them and 'inject' it into your classes.
If you don't want to use any framework, you can take design notes from them and try to emulate their design patterns and tweak it for your use-case.
Also, you can simplify things to a certain extent by making proper use of Collections. For example, what additional feature does Offers have other than storing a collection of Offer? I'm not sure what your constraints there are but, if you can make that part a bit more cleaner you would have massive gains in all places where you are instantiating the objects.
Dozer framework provides nice way to do copy values from ws object to your dto. Here is another example. Additionally if the getter/setter names are the same of both class you dont need custom converter
I've created simple annotation in Java
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Column {
String columnName();
}
and class
public class Table {
#Column(columnName = "id")
private int colId;
#Column(columnName = "name")
private String colName;
private int noAnnotationHere;
public Table(int colId, String colName, int noAnnotationHere) {
this.colId = colId;
this.colName = colName;
this.noAnnotationHere = noAnnotationHere;
}
}
I need to iterate over all fields, that are annotated with Column and get name and value of field and annotation. But I've got problem with getting value of each field, since all of them are of different data type.
Is there anything that would return collection of fields that have certain annotation?
I managed to do it with this code, but I don't think that reflection is good way to solve it.
Table table = new Table(1, "test", 2);
for (Field field : table.getClass().getDeclaredFields()) {
Column col;
// check if field has annotation
if ((col = field.getAnnotation(Column.class)) != null) {
String log = "colname: " + col.columnName() + "\n";
log += "field name: " + field.getName() + "\n\n";
// here i don't know how to get value of field, since all get methods
// are type specific
System.out.println(log);
}
}
Do I have to wrap every field in object, which would implement method like getValue(), or is there some better way around this? Basicly all I need is string representation of each field that is annotated.
edit: yep field.get(table) works, but only for public fields, is there any way how to do this even for private fields? Or do I have to make getter and somehow invoke it?
Every object should has toString() defined. (And you can override this for each class to get a more meaningful representation).
So you where your "// here I don't know" comment is, you could have:
Object value = field.get(table);
// gets the value of this field for the instance 'table'
log += "value: " + value + "\n";
// implicitly uses toString for you
// or will put 'null' if the object is null
Reflection is exactly the way to solve it. Finding out things about types and their members at execution time is pretty much the definition of reflection! The way you've done it looks fine to me.
To find the value of the field, use field.get(table)
Reflection is exactly the way to look at annotations. They are a form of "metadata" attached to the class or method, and Java annotations were designed to be examined that way.
Reflection is one way to process the object (probably the only way if the fields are private and don't have any kind of accessor method). You'll need to look at Field.setAccessible and perhaps Field.getType.
Another approach is to generate another class for enumerating the annotated fields using a compile-time annotation processor. This requires a com.sun API in Java 5, but support is better in the Java 6 JDK (IDEs like Eclipse may require special project configuration).