I am trying to write a custom exception with 3 constroctors. Can I initize final variables in 3 different constroctors? I am getting compilation errors. How to make this error free?
public class CrifServiceFaultException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public CrifServiceFaultException(String message) {
// // - The blank final field errorDescription may not have been
super(message);
}
public CrifServiceFaultException(String processCode,
String processDescription, String transformCode,
String transformDescription) {
// - The blank final field errorDescription may not have been
initialized
super(processDescription + " " + transformDescription);
this.processCode = processCode;
this.processDescription = processDescription;
this.transformCode = transformCode;
this.transformDescription = transformDescription;
}
public CrifServiceFaultException(String errorCode, String errorDescription) { // The blank final field transformDescription may not have been initialized
super(errorDescription);
setErrorCode(errorCode);
setErrorDescription(errorDescription);
}
final private String processCode;
final private String processDescription;
final private String transformCode;
final private String transformDescription;
final private String errorCode;
final private String errorDescription;
// getters are here
}
Because, according to Java specifications, every final variable must be initialized before the end of the constructor.
In your case in each constructor you leave some of them uninitialized (formally they're blank). In short you have to set a value for them (even when unused in a specific constructor):
public CrifServiceFaultException(String message)
{
super(message);
processCode = "";
processDescription = "";
transformCode= "";
transformDescription= "";
errorCode= "";
errorDescription= "";
}
public CrifServiceFaultException(String processCode,
String processDescription, String transformCode,
String transformDescription)
{
super(processDescription + " " + transformDescription);
this.processCode = processCode;
this.processDescription = processDescription;
this.transformCode = transformCode;
this.transformDescription = transformDescription;
errorCode= "";
errorDescription= "";
}
public CrifServiceFaultException(String errorCode, String errorDescription)
{
super(errorDescription);
setErrorCode(errorCode);
setErrorDescription(errorDescription);
processCode = "";
processDescription = "";
transformCode= "";
transformDescription= "";
}
Note that even documentation says that:
...Declaring a variable final can serve as useful documentation...
From such sentence what we can guess is that final is only a decoration useful to avoid trivial mistakes at compile time (practically pretty similar to what const is in C++). Anyway IMO we shouldn't ever assume final variables are mutable (even through JNI) because they may enable strong optimizations at run-time (I'm thinking specifically about HotSpot): think about concurrent access and cache coherency (especially for primitive types).
Related
I have lots of classes representing user screens in the application that I am testing (page objects). Each of the page objects contains various number of elements with wach of the having an ID. I need to declare those IDs. It looks something like this:
public class MessagesScreen extends BasePage {
private static final String backArrowButtonID = PACKAGE_NAME_ID + "backArrow";
private static final String noMessagesImageID = PACKAGE_NAME_ID + "empty_messages_icon";
private static final String noMessagesTextViewI = PACKAGE_NAME_ID + "label_no_documents";
private static final String errorTextViewID = PACKAGE_NAME_ID + "text_error_response";
private static final String progressBarID = PACKAGE_NAME_ID + "message_list_progress_bar";
private static final String messagesRecyclerViewID = PACKAGE_NAME_ID + "messageList";
private static final String swipeRefreshLayoutID = PACKAGE_NAME_ID + "swipeRefreshLayout";
private static final String instantMessageLayoutID = PACKAGE_NAME_ID + "item_instant_message_layout";
}
Each of the IDs needs to have the an environmental variable added as above.
My question is: is there any nifty way of not having to repeat this PACKAGE_NAME_ID all the time? Is there a way of automatic assigning the constant string to every new class field?
Using an enum here will improve your code in many ways. In addition to solving your current problem, you'd be using the right tool for constants.
enum IdKey {
BACK_ARROW_BUTTON_ID("backArrow"),
NO_MESSAGES_IMAGE_ID("empty_messages_icon"),
NO_MESSAGES_TEXT_VIEW_ID("label_no_documents"),
ERROR_TEXT_VIEW_ID("text_error_response"),
PROGRESS_BAR_ID("message_list_progress_bar"),
MESSAGES_RECYCLER_VIEW_ID("messageList"),
SWIPE_REFRESH_LAYOUT_ID("swipeRefreshLayout"),
INSTANT_MESSAGE_LAYOUT_ID("item_instant_message_layout");
private final String suffix;
private IdKey(String suffix) {
this.suffix = suffix;
}
public String getSuffix() {
return BasePage.PACKAGE_NAME_ID + this.suffix;
}
}
And all you'd have to do wherever you were using your fields is just call:
IdKey.BACK_ARROW_BUTTON_ID.getSuffix();
And the code is both more reliable and cleaner. You can even nest the enum as a private member of MessagesScreen.
I might consider an enum in this case, you can still reference a specific value in the code and override the toString to return your message in the format you want
I have lots of classes representing user screens in the application that I am testing (page objects). Each of the page objects contains various number of elements with wach of the having an ID. I need to declare those IDs. It looks something like this:
public enum MessagesScreen {
BACK_ARROW("backArrow"),
NO_MESSAGES_IMAGE("empty_messages");
private String value;
private Messages(String value) {
this.value = value;
}
#Override public String toString() {
return PACKAGE_NAME_ID + this.value;
}
}
As you cannot enrich the state of final variables after their valuing, I would do things in the other way : providing a getter that adds the desired prefix.
public class MessagesScreen extends BasePage {
private static final String backArrowButtonID = "backArrow";
private static final String noMessagesImageID = "empty_messages_icon";
///...
public String getIdWithPrefix(String constantValue){
return PACKAGE_NAME_ID + constantValue;
}
}
Note that with an enum it would be more robust as Strings accept a very large range of possible values whereas enums don't.
It will require you to change many classes but it is worthful.
The ernest_k answer shows that very well.
In this code, if I add 'final' to the variable definitions, I will receive "the final fields may have not been initialized" error. Some suggested solutions on Statckoverflow tend to be creating static functions to return the value. However, in this case I need to create four different functions to do that. Is there a more elegant solution to this issue?
private static String MODEL_PATH;
private static String VECTORS_PATH;
private static String NEG_PATH;
private static String POS_PATH;
static {
try {
MODEL_PATH = new ClassPathResource("models/word2vec_model").getFile().getAbsolutePath();
VECTORS_PATH = new ClassPathResource("models/model.zip").getFile().getAbsolutePath();
NEG_PATH = new ClassPathResource("models/neg.txt").getFile().getAbsolutePath();
POS_PATH = new ClassPathResource("models/pos.txt").getFile().getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
}
}
However, in this case I need to create four different functions to do that.
Since you are doing essentially the same thing, but with different resource names, one method would be sufficient:
private static String getResourceByName(string path) {
try {
return ClassPathResource(path).getFile().getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Now you can use the same method four times in your initialization:
private static final String MODEL_PATH = getResourceByName("models/word2vec_model");
private static final String VECTORS_PATH = getResourceByName("models/model.zip");
private static final String NEG_PATH = getResourceByName("models/neg.txt");
private static final String POS_PATH = getResourceByName("models/pos.txt");
I want to generate custom getters and setter, so I can handle variables better when I will be saving these instances into SQL database. I want to generate something like:
public class Test extends SQLEntry {
private static final String NAME = "Name";
public String getName() {
return get(NAME);
}
public void setName(String name) {
set(NAME, name);
}
}
But as I can see in Eclipse it generates only the following code:
public class Test {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Is there some plugin, that can do it? Or am I missing something?
I have like 20 classes and I will not write this manually.
I dont know why you need this, but here is the approach to custom Getters and Setters.
You can update all generated setters and getters by going to preferences > java > Code Style > code Templates and selecting code then edit Getter body and Setter body and put this:
Getter body: return get(${field});
Setter body: set(${field}, ${param});
Let me know if that works
I recommend that instead of doing what you describe, you should use Spring Data. Specifically the BeanPropertyRowMapper class in the org.springframework.jdbc.core package will do what you want.
Read more in the Spring API documentation.
there is no other plugin available!
how can some plugin write code that is specific to your business logic!
you have to write the code manually for setters and getters in all the classes!
Try write-it-once. Template based code generator. You write custom template using Groovy, and generate file depending on java reflections. It's the simplest way to generate any file. You can make getters/settest/toString by generating AspectJ or java files, SQL based on JPA annotations, inserts / updates based on enums and so on.
On the end I found it that it is the best to do it your self...
If you like writing a code than you will enjoy this solution the most.
public class CodeGenerator {
private final static String ENCODING = "UTF-8";
private final static String FILE_NAME = "File.txt";
public static void main(String[] args) {
try {
ArrayList<Carriage> names = getNames();
for (Carriage c : names) {
createSetter(c.name, c.capitalName);
createGetter(c.name, c.capitalName);
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
}
private static ArrayList<Carriage> getNames() throws FileNotFoundException {
File file = new File("/");
InputStream is = CodeGenerator.class.getResourceAsStream(FILE_NAME);
Scanner s = new java.util.Scanner(is, ENCODING).useDelimiter("\\A");
String content = s.next();
String[] lines = content.split(System.getProperty("line.separator"));
ArrayList<Carriage> ret = new ArrayList<Carriage>();
for (String line : lines) {
line = line.replaceAll("\\r", "");
int firstCapitalIndex = line.indexOf("String") + 7;
int secondCapitalIndex = line.indexOf(" ", firstCapitalIndex);
int firstIndex = line.indexOf("\"") + 1;
int secondIndex = line.indexOf("\"", firstIndex + 1);
Carriage c = new Carriage();
c.name = line.substring(firstIndex, secondIndex);
c.capitalName = line.substring(firstCapitalIndex, secondCapitalIndex);
ret.add(c);
}
return ret;
}
public static void createSetter(String name, String capitalName) {
String str = "public void set" + name + "(String val) {\n"
+ "\tset(" + capitalName + ", val);\n"
+ "}\n";
System.out.println(str);
}
public static void createGetter(String name, String capitalName) {
String str = "public String get" + name + "() {\n"
+ "\treturn (String) get(" + capitalName + ");\n"
+ "}\n";
System.out.println(str);
}
carriage:
package codegenerator;
public class Carriage {
public String name;
public String capitalName;
}
And to File.txt I just coppy all defined constants and run the generator...
public static final String NAME = "Name";
public static final String PHONE = "Phone";
public static final String EMAIL = "Email";
public static final String ADDRESS_1 = "Address1";
public static final String ADDRESS_2 = "Address2";
public static final String ADDRESS_3 = "Address3";
public static final String ICO = "Ico";
public static final String DIC = "Dic";
public static final String ADMIN_LOGIN = "AdminLogin";
public static final String ADMIN_PASSWORD = "AdminPassword";
public static final String LANGUAGE = "Language";
public static final String CODE = "CODE";
public static final String MONTHLY_PAYMENT = "MonthlyPayment";
I'm really not sure why it's doing this but it seems to be an issue with brackets.
I'm getting the following errors while running this segment of code for Android in Eclipse:
private static final String TWITTER_ACCESS_TOKEN_URL = "http://api.twitter.com/oauth/access_token";
private static final String TWITTER_AUTHORZE_URL = "https://api.twitter.com/oauth/authorize";
private static final String TWITTER_REQUEST_URL = "https://api.twitter.com/oauth/request_token";
public static final String itemOfClothing;
public static final String clothingEmotion;
public static final String user;<<<<<<<<<<<<<<<<<<<<< Syntax error on token ";", { expected after this token
itemOfClothing = "pants";
clothingEmotion = "I'm feeling left in the dark";
user = "stuart";
public static String MESSAGE = itemOfClothing +": " + clothingEmotion + "! #" + user + "EmotionalClothing"; <<<<<<<<<<<<<<<<<<<<<< Syntax error, insert "}" to complete Block
public TwitterApp(Activity context, String consumerKey, String secretKey) {
this.context = context;
You should initialize your strings at the point of declaration only, or inside a constructor. You can't have statements at the top-level class. You can just have declarations there.
So, one solution is, change the below statements: -
public static final String itemOfClothing;
public static final String clothingEmotion;
public static final String user;
/** You can't have below assignments directly under the top-level class **/
itemOfClothing = "pants";
clothingEmotion = "I'm feeling left in the dark";
user = "stuart";
to: -
public static final String itemOfClothing = "pants";
public static final String clothingEmotion = "I'm feeling left in the dark";
public static final String user = "stuart";
Or, another solution is, to move those assignments in a constructor, in which case, you would have to move the initialization of MESSAGE also in that constructor.
And also, if those variables are supposed to be constants, which I assume they are, as they are public static final, then your should use ALL_CAPS_WITH_UNDERSCORE to name them.
this is the issue at hand, when trying to serialize the class below with the code below i'm getting is the below xml file without all the strings in the class.
The Class (some static values have changed but basically it), I left out all the generated get\set but they are all there with public access modifiers.
public class NotificationConfiguration implements Serializable
{
public static final String PORT_KEY = "mail.smtp.port";
public static final String DEFAULT_PORT_VALUE = "587";
public static final String TTL_KEY = "mail.smtp.starttls.enable";
public static final String DEFAULT_TTL_VALUE = "true";
public static final String AUTH_KEY = "mail.smtp.auth";
public static final String DEFAULT_AUTH_VALUE = "true";
public static final String MAIL_SERVER_KEY = "mail.smtp.host";
public static final String DEFAULT_MAIL_CLIENT_HOST = "smtp.gmail.com";
public static final String DEFAULT_MAIL_CLIENT_USERNAME = "*********";
public static final String DEFAULT_MAIL_CLIENT_PASSWORD = "*********";
public static final String DEFAULT_MAIL_CLIENT_ADDRESS = "*********";
public static final String DEFAULT_ADMIN_EMAIL = "*********";
public static final long DEFAULT_MAIL_INTERVAL = 24*60*60*1000; //One time a day default
public static final String SAVED_FOLDER_NAME = "C:\\Library";
public static final String SAVED_FILE_NAME = "C:\\Library\\NotificationCfg.xml";
private String portValue = DEFAULT_PORT_VALUE;
private String ttlValue = DEFAULT_TTL_VALUE;
private String authValue = DEFAULT_AUTH_VALUE;
private String mailClientHost = DEFAULT_MAIL_CLIENT_HOST;
private String mailClientUserName = DEFAULT_MAIL_CLIENT_USERNAME;
private String mailClientPassword = DEFAULT_MAIL_CLIENT_PASSWORD;
private String mailClientAddress = DEFAULT_MAIL_CLIENT_ADDRESS;
private String adminEMail = DEFAULT_ADMIN_EMAIL;
private boolean overdueSubsNotificationEnabled = false;
private boolean adminReportNotificationEnabled = false;
private long mailInterval =
}
The code used to serialize, which also creates the folder if missing.
public void storeChanges()
{
try
{
try
{
File f = new File(NotificationConfiguration.SAVED_FOLDER_NAME);
f.mkdir();
}
catch (Exception e){}
XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream(new FileOutputStream(NotificationConfiguration.SAVED_FILE_NAME)));
encoder.writeObject(notificationConfig);
encoder.close();
System.out.println(LOG_CONFIGURATION_STORED);
}
catch (Exception ex)
{
System.out.println(LOG_CONFIGURATION_NOT_STORED + ex.getMessage());
}
}
The XML file received, with no exceptions thrown while serializing.
It basically just has the long value.
XMLEncoder encodes information about how to restore your object. If field values haven't changed from their defaults, XMLEncoder doesn't store anything.
This can cause confusion.
Hence, my rules of thumb when using XMLEncoder are:
1. don't initialize fields. don't do private String foo = DEFAULT_FOO;
2. don't do anything in the default constructor.
3. have some other method, or factory that will give you a "default" setup if needed.
I highly recommend to read again the XMLEncoder Javadoc
I will point out the main differences with the binary serialization we all know.
to restore the instance it need the class definition available to the JVM
It serializes only the data. And only the modified from default data.
As result of the 2 points above - is that there is no reason to serialize Static final values - they are part of the class definition.
The binary serialization on the other hand does serialize the class definition and can load from byte stream a class that was not available to the JVM before.
That is why you got results that you see. It Ok this is behavior by design and you use it right. It seems just not to be what you need.
By the way see what Xstream has to offer.
What is SAVED_FOLDER_NAME ? Is that like a factory object and did you by any chance call setMailInterval on that object?
Could that be that only mailInterval has a getter?
Just looked again the question apparently there is getter for all fields so ...