Working with Protocol Buffers and internal data models - java

I have an existing internal data model for a Picture, as follows:
package test.model;
public class Picture {
private int height, width;
private Format format;
public enum Format {
JPEG, BMP, GIF
}
// Constructor, getters and setters, hashCode, equals, toString etc.
}
I now want to serialize it using protocol buffers. I've written a Picture.proto file that mirrors the fields of the Picture class and compiled the code under the test.model.protobuf package with a classname of PictureProtoBuf:
package test.model.protobuf;
option java_package = "test.model.protobuf";
option java_outer_classname = "PictureProtoBuf";
message Picture {
enum Format {
JPEG = 1;
BMP = 2;
GIF = 3;
}
required uint32 width = 1;
required uint32 height = 2;
required Format format = 3;
}
Now I am now assuming that if I have a Picture that I want to serialize and send somewhere I have to create a PictureProtoBuf object and map all the fields across, like so:
Picture p = new Picture(100, 200, Picture.JPEG);
PictureProtoBuf.Picture.Builder output = PictureProtoBuf.Picture.newBuilder();
output.setHeight(p.getHeight());
output.setWidth(p.getWidth());
I'm coming unstuck when I have an enumeration in my data model. The ugly way that I'm using right now is:
output.setFormat(PictureProtoBuf.Picture.Format.valueOf(p.getFormat().name());
However, this is prone to breakage and relies on the enumeration name being consistent between my internal data model and the protocol buffer data model (which isn't a great assumption as enumeration names within .proto files need to be unique). I can see me having to hand-craft switch statements on enumerations if the .name() call from the internal model doesn't match the protobuf-generated enumeration name.
I guess my question is whether I'm going about this the right way? Am I supposed to scrap my internal data model (test.model.Picture) in favour of the protobuf-generated one (test.model.protobuf.PictureProtoBuf)? If so, how can I implement some of the niceties that I have done in my internal data model (e.g. hashCode(), equals(Object), toString(), etc.)?

Although the existing answers are good, I decided to go a bit further with Marc Gravell's suggestion to look into protostuff.
You can use the protostuff runtime module along with the dynamic ObjectSchema to create schemas at runtime for your internal data model
My code now reduces to:
// Do this once
private static Schema<Picture> schema = RuntimeSchema.getSchema(Picture.class);
private static final LinkedBuffer buffer = LinkedBuffer.allocate(DEFAULT_BUFFER_SIZE);
// For each Picture you want to serialize...
Picture p = new Picture(100, 200, Picture.JPEG);
byte[] result = ProtobufIOUtil.toByteArray(p, schema, buffer);
buffer.clear();
return result;
This is a great improvement over the Google protobuf library (see my question) when you have lots and lots of attributes in your internal data model. There is also no speed penalty that I can detect (with my use cases, anyway!)

If you have control over your internal data model, you could modify test.model.Picture so that the enum values know their corresponding protobuf equivalent, probably passing in the correspondence to your enum constructors.
For example, using Guava's BiMap (bidirectional map with unique values), we get something like
enum ProtoEnum { // we don't control this
ENUM1, ENUM2, ENUM3;
}
enum MyEnum {
ONE(ProtoEnum.ENUM1), TWO(ProtoEnum.ENUM2), THREE(ProtoEnum.ENUM3);
static final ImmutableBiMap<MyEnum, ProtoEnum> CORRESPONDENCE;
static {
ImmutableBiMap.Builder<ProtoEnum, MyEnum> builder = ImmutableBiMap.builder();
for (MyEnum x : MyEnum.values()) {
builder.put(x.corresponding, x);
}
CORRESPONDENCE = builder.build();
}
private final ProtoEnum corresponding;
private MyEnum(ProtoEnum corresponding) {
this.corresponding = corresponding;
}
}
and then if we want to look up the MyEnum corresponding to a ProtoEnum, we just do MyEnum.CORRESPONDENCE.get(protoEnum), and to go the other way, we just do MyEnum.CORRESPONDENCE.inverse().get(myEnum) or myEnum.getCorresponding().

One way is to only keep the generated enum:
package test.model;
public class Picture {
private int height, width;
private PictureProtoBuf.Picture.Format format;
// Constructor, getters and setters, hashCode, equals, toString etc.
}
I've used this a few times, it may or may not make sense in your case. Using the protobuf generated classes as you data model (or extending them to add functionality), is never recommended, though.

Related

Object differ hasChanges where no changes should be detected

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!

Inheritance in protocol buffers

How to handle inheritance in Google Protocol Buffers 3.0?
Java equivalent code:
public class Bar {
String name;
}
public class Foo extends Bar {
String id;
}
What would be Proto equivalent code?
message Bar {
string name = 1;
}
message Foo {
string id = 2;
}
Protocol Buffers does not support inheritance. Instead, consider using composition:
message Foo {
Bar bar = 1;
string id = 2;
}
However, that said, there is a trick you can use which is like inheritance -- but which is an ugly hack, so you should only use it with care. If you define your message types like:
message Bar {
string name = 1;
}
message Foo {
string name = 1;
string id = 2;
}
These two types are compatible, because Foo contains a superset of the fields of Bar. This means if you have an encoded message of one type, you can decode it as the other type. If you try to decode a Bar as type Foo, the field id will not be set (and will get its default value). If you decode a Foo as type Bar, the field id will be ignored. (Notice that these are the same rules that apply when adding new fields to a type over time.)
You can possibly use this to implement something like inheritance, by having several types all of which contain a copy of the fields of the "superclass". However, there are a couple big problems with this approach:
To convert a message object of type Foo to type Bar, you have to serialize and re-parse; you can't just cast. This can be inefficient.
It's very hard to add new fields to the superclass, because you have to make sure to add the field to every subclass and have to make sure that this doesn't create any field number conflicts.
See the Protocol Buffer Basics tutorial:
Don't go looking for facilities similar to class inheritance, though – protocol buffers don't do that.

Create JSON File Serializing the class in Java

I have the following class:
public class PDFValues {
private String value;
private int xPos;
private int yPos;
public PDFValues(){
}
public PDFValues(String value, int x, int y){
this.setValue(value);
this.setX(x);
this.setY(y);
}
public void setValue(String value){
this.value = value;
}
public void setX(int x){
this.xPos = x;
}
public void setY(int y){
this.yPos = y;
}
public String getValue(){
return this.value;
}
public int getX(){
return this.xPos;
}
public int getY(){
return this.yPos;
}
}
And then I want to do this:
public class PDFtoJSONTest {
public static void main(String[] args) {
List<PDFValues> listaElementos = new ArrayList<PDFValues>();
listaElementos.add(new PDFValues("Anubis Lockward Botello",
new Integer(100), new Integer(633)));
....more code
}
}
What I want to do, is save all the PDFValues in the ArrayList, as a JSON file, but I don't know how to make it automatic, I thought of Serializing the object or something, but I can't find a solution to this and I'm not sure how I could make the PDFValues object serializable.
I want to do this to save those values in a JSON file and then use them as properties to generate a PDF file, I'm using PDFBox for the generation of the PDFs files and SimpleJSON for the .json ones.
I'm working on a project where I'd have to generate thousands of pdf files out of some processed data. I've already managed to parse the data which consists of about 500+ MBs of text and holds around five thousand account statements which need to be generated as PDFs.
The thing is, that seeings as the Text data is generated in PDFs, one needs to indicate the position of the starting character in a string to PDFValues, to generate a PDFTextInfo object and then add it to the PDF, the file would need to contain images and text and other stuff.
Note: If there's a better way to accomplish what I'm trying to do, I'm open to suggestions, but I'd also like an answer to what I'm trying to do, and know if it would work or not, and why for both cases.
I'd like to make my code as fast as possible, right now I'm able to process the whole TXT file from RAW to mostly clean data in under 2 minutes and I know it might be optimized but right now that's not the point :D
I'd like to generate the PDFs files as fast as possible, but I've been working with that project in Java for like 1 1/2 months now, and I've only learned about JSON and PDF file generation in the past week...it's been three days of working on the JSON file and I'm a bit lost.
Here's an example of the file output for the JSON file that I'm trying to accomplish, this one I generated it manually and I managed to read and process the file, now I'm trying to generate it automatically:
{
"Header": {
"FullName":
{
"Name":"Anubis Lockward Botello",
"Horizontal":180,
"Vertical":633
},
..... more elements .....
}
}
As you can see, I'm trying to divide the elements on the pdf files as if they were panels, like HEADER, BALANCES, TRANSACTIONS and stuff, and build the PDF file as if they were pieces of a puzzle, but right now I'm trying to "build" the name element on the header.
I would guess there is a better way to do build PDF files than writing and then re-reading a file, but I can provide one answer for your JSON question.
Use the Apache commons-lang3 library and look into ToStringBuilder. You can then define a toString() method on your object and use the built-in ToStringStyle.JSON_STYLE format. You'd then have to wrap your list of PDFValues in some other object that can store a PDFValue for Header, FullName, etc..
#Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE)
.append("Name", value)
.append("Horizontal", xPos)
.append("Vertical", yPos)
.toString();
}
I should note that you could pull in Jackson or similar libraries, annotate your objects with the required JsonProperty annotations and use the library to serialize your object to JSON as you would for REST or similar. But, for a simple use case like yours, the ToStringBuilder is simple and effective.
OK, I managed to get this far thanks to JudgingNotJudging, what I did was taking his answer and applying a Decorator Pattern to the object, so that I have a PDFValue, that's inside a PDFElement, that's part of a PDFContainer, so it goes like this:
Header: (this is our PDFContainer)
FullName: (so, Header HAS-A FullName element)
PDFValue: (and FullName HAS-A a PDFValue, that has the Name or value to be shown, and the X and Y coordinates inside the PDF)
Here's the code:
The PDFValue class is still the same, and I added the overridden toString() method according to JudgingNotJudging's answer.
public class PDFValuesDecorator extends PDFValues{
}
In PDFValuesDecorator we don't do anything, we're just going to extend PDFValues so that we have the correct type of the class we want to add behavior to, and still get a common type for all the different classes we might create this way.
public class PDFElement extends PDFValuesDecorator {
private PDFValues pdfValue;
private String elementID;
public PDFElement(PDFValues pdfValue, String elementID){
this.pdfValue = pdfValue;
this.elementID = elementID;
}
#Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE)
.append(elementID, pdfValue.toString())
.toString();
}
}
In the constructor we save the instance of the object we're trying to "wrap" so that we can "add" something to it. In this case, we're adding an ID for the element and we're modifying the toString() method of the element to also include the toString() method of the PDFValue, so that they both show both of their values in the appropriate order.
Finally, here's my main method:
public class PDFtoJSONTest {
public static void main(String[] args) {
List<PDFValues> listaElementos = new ArrayList<PDFValues>();
PDFValues name =
new PDFValues(
"Anubis Lockward Botello",
new Integer(100),
new Integer(633)
);
PDFElement fullName = new PDFElement(name, "FullName");
PDFElement header = new PDFElement(fullName, "Header");
listaElementos.add(header);
for(PDFValues value : listaElementos){
System.out.println("Valor: " + value.toJSONString());
}
}
}
As you can see, the first thing I do is create an ArrayList of PDFValues, then I create a single object for the name value, then that name is wrapped inside the FullName element, and then that's stored inside a Header element. As you can see, I can pass around the List object and do with it whatever I want.
And also, I could create other PDFElements like images and stuff, and I can save all of them inside the ArrayList and pass them around and then when I want to save them, I just have to call the toString method once and I would get the correct output, btw, here's the resulting value from the JSON string:
Valor: {"Header":"{"FullName":"{"Name":"Anubis Lockward Botello","Horizontal":100,"Vertical":633}"}"}

How do I initialize classes with lots of fields in an elegant way?

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

Best practice for maintaining constants in Java

I have an old doubt about constants in Java Projects maintenance. From my perspective, when we try putting the constants inside an Abstract class like that:
public final class MyConstants {
public static final String CONSTANT1 = "const1";
public static final String CONSTANT2 = "const2";
public static final String CONSTANT3 = "const3";
public static final String CONSTANT4 = "const4";
}
after that using those constants inside classes in the project:
public void myMethod(final Map params) {
final String myparam = (String) params.get(MyConstants.CONSTANT1);
//DO SOMETHING WITH PARAMS
}
It leads to boiler plate code, verbose use of constants and no real advances. In other hand if we put those constants inside the class for somehow people don't like it. They say "what about we have the same constant declare somewhere?" the problem is maintainance issues, if we change those constants in that class the change can be visible on several parts without any big problem.
Those constants are mainly used for mapping webservices for java perspective without having to generating POJOs like JAXB based on WSDL, the webservices operations are mapped directly for key value maps in Java.
I want to know what do you think about this approach and if we have any other choice.
Thank you.
If I understand your concern, don't hardcode those constants as values except perhaps as defaults and store them with Properties and/or ResourceBundle(s). You might also read the Java Tutorial on Properties. Something like,
Properties props = new Properties();
FileInputStream in = new FileInputStream("my.proprties");
props.load(in);
String v = props.get("CONSTANT_ONE", "const1"); // <-- the "1" is a default.
Then if you need to change the property later you only have to modify the properties file.

Categories

Resources