I have duplicated code in my program, I have enums that load values from a property file, I want make my code to be cleaner.
Maybe an Interface can be the solution but I can't declare a non final variable.
This is an example:
public enum AlertMessageEnum{
//
OUTPUT_FOLDER_EXISTS,
...
CONFIG_FILE_IS_MISSING;
// the file path to load properties
private static final String PATH= "/i18n/alertDialogText.properties";
private static Properties properties;
private String value;
public void init() {
if (properties == null) {
properties = new Properties();
try {
properties.load(AlertMessageEnum.class.getResourceAsStream(PATH));
}
catch (Exception e) {
throw new RthosRuntimeException(e);
}
}
value = (String) properties.get(this.toString());
}
public String getValue() {
if (value == null) {
init();
}
return value;
}
}
public enum ConverterErrorEnum{
INVALID_EXTRACTION_PATH,
...
PATIAL_DATA_GENERATED;
private static final String PATH= "/i18n/converterErrorText.properties";
private static Properties properties;
private String value;
...
}
It's impossible to generate enums from property file with normal java code. You need a workaround, like:
use a class that publishes these constants aws immutable values
generate java source code from property file
generate java code with reflection
I suggest option 1. E.g. with singleton:
package com.example;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
public class Props {
private static Props INSTANCE;
public synchronized Props getInstance() {
if (INSTANCE == null) {
INSTANCE = new Props();
}
return INSTANCE;
}
private static final String PATH = "/i18n/converterErrorText.properties";
private Properties properties;
private List<String> keys;
public Props() {
properties = new Properties();
keys = new ArrayList<>();
try {
properties.load(getClass().getResourceAsStream(PATH));
for (Object key : properties.keySet()) {
keys.add(key.toString());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Enumeration<Object> getKeys() {
return properties.keys();
}
public String getProperty(String key) {
return properties.getProperty(key);
}
}
Delegate to another class that holds Properties for all the enums:
public class PropertyProvider {
private static Map<Class<?>, Properties> pMap = new HashMap<>();
public static String getValue(Enum<?> enumValue, final String path) {
Properties properties = pMap.get(enumValue.getClass());
if (properties == null) {
properties = new Properties();
try {
properties.load(PropertyProvider.class.getResourceAsStream(path));
}
catch (Exception e) {
throw new RthosRuntimeException(e);
}
pMap.put(enumValue.getClass(), properties);
}
return (String) properties.get(enumValue.toString());
}
}
public enum ConverterErrorEnum{
INVALID_EXTRACTION_PATH,
...
PATIAL_DATA_GENERATED;
private static final String PATH= "/i18n/converterErrorText.properties";
private String value;
...
public String getValue() {
if (value == null) {
value = PropertyProvider.getValue(this, PATH);
}
return value;
}
}
Related
I want to create a singleton in Java that requires reading from a file configuration to instanciate, amongst other logic (so it's not just a new MySingletonObject()).
What's the proper way to achieve that in Spring ? I was wondering if I should do the following:
public interface MySingletonObjectAccessor {
MySingletonObject getInstance();
}
#Service
public class MySingletonObjectAccessorImpl implements MySingletonObjectAccessor {
private MySingletonObject mySingletonObject;
#Override
public MySingletonObject getInstance() {
return mySingletonObject;
}
MySingletonObjectAccessorImpl() {
this.MySingletonObject = // complex logic here, that includes reading from a config file
}
}
the usage would then be:
#Autowired
MySingletonObjectAccessor msoa;
MySingletonObject mso = msoa.getInstance();
Am I on the right track ? If so, what would be the correct naming convention for the MySingletonObjectAccessor service ?
You can define a Bean and add a scope to make it singleton.
#Configuration
class MySingletonBeanConfiguration {
//default is singleton scope
#Bean
public MySingletonBean mySingletonBean() {
return new MySingletonBean();
}
}
You could have a public Configuration class like this in your Spring-scanned packages:
#Configuration
public class MySingletonProvider {
#Bean
public MySingleton nameTheMethodExactlyLikeTheBeanNameYouWant(#Value("${singleton.xml.file}") String xmlConfigFile) {
Library lib = new Library(xmlConfigFile);
return new MySingleton(lib);
}
}
If you are using singleton as config then use #Component and use #Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) for singleton.
If it is configuring a file the use FileConfig as class name, as per java standards class name must specify the what it have and what it can do. Ex:- FileReadConfig, FileUploadConfig, DBConnectConfig, EagerInitializedSingleton, StaticBlockSingleton, EnumSingleton ....,
Example:-
#Configuration
public class MySingletonObject {
private MySingletonObject mySingletonObject;
public static final String FILENAME = "/Users/xxx/Projects/xxx/config.xml";
private XMLObject config = null;
private boolean loadConfig(String fileName) {
BufferedReader reader;
String line;
String content = "";
try {
reader = new BufferedReader(new FileReader(fileName));
while ((line = reader.readLine()) != null) {
content += line;
}
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
return false;
}
/**
* IF there is no content, the file must not be valid
*/
if (content.length() <= 0) {
return false;
}
this.config = new XMLObject(content);
return true;
}
private Configuration() {
boolean result = this.loadConfig(FILENAME);
if (!result) {
if (!this.createConfig(FILENAME)) {
System.exit(0); //Catastrophic
}
}else{
mySingletonObject = new MySingletonObject ();
}
}
#Bean("mySingletonObject")
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public MySingletonObject getMySingletonObject () {
return mySingletonObject;
}
}
Now
#Autowired
MySingletonObject msoa;
How to write this Java Class in C# Class format
public final class JsonParserResolver {
// PlacesApiJsonParser is an Interface
public static final PlacesApiJsonParser JSON_PARSER;
static {
boolean hasGson;
try {
Class.forName("com.google.gson.Gson");
hasGson = true;
} catch (ClassNotFoundException e) {
hasGson = false;
}
JSON_PARSER = hasGson ? new GsonPlacesApiJsonParser() : new
AndroidPlacesApiJsonParser();
}
private JsonParserResolver() {
throw new RuntimeException("No instances");
}
}
The class static member is resolving stuff automatically on Class instantiation. This is a very useful
Hold your horses this is where I am, I get a little stuck on the JSON_PARSER
namespace WorkSampleBookSearch
{
public final class JsonParserResolver
{
public static final PlacesApiJsonParser JSON_PARSER;
static {
boolean hasGson;
JSON_PARSER = hasGson? new GsonPlacesApiJsonParser() : new AndroidPlacesApiJsonParser();
}
private JsonParserResolver()
{
throw new RuntimeException("No instances");
}
}
}
My singleton is called Resources. It should only be instantiated once by this Singleton standard I used:
package site.kevindhu.models;
import site.kevindhu.entity.Player;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class Resources {
public static Resources resources;
public Map<String, Object> data;
static {
resources = new Resources();
}
private Resources() {
data = new HashMap<>();
data.put("players", new HashSet<Player>());
data.put("newPlayers", new HashSet<Player>());
}
public static Resources getInstance() {
return resources;
}
}
However, it is not working correctly!
When I deploy a .ear to run my glassfish server, it goes into this block twice:
static {
resources = new Resources();
}
As a result, the "singleton" actually creates two different Resources each time I run the server.
I know I do twice because I debug it calls two different Resources objects whenever I attempt to call Resources.resources.
Is this possibly because I am deploying a .ear file? How do the specifics of this double instantiation work?
The best way to go is to let the compiler handle it for you:
/** Singleton. */
public enum Resources {
RESOURCES;
private final Map<String, Team> teams = new HashMap<>();
public boolean add(Team team) {
return team != null
&& teams.put(team.getName(), team) == null;
}
public Team find(String name) {
return name == null ? null : teams.get(name);
}
public Team find(Team team) {
return team == null ? null : get(team.getName());
}
public Map<String, Team> getTeams() {
return Collections.unmodifiableMap(teams);
}
// remove, iterators, etc.
}
public class TeamImpl implements Team {
private final String name;
private final Map<String, Player> roster = new HashMap<>();
public TeamImpl(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
this.name = name;
assert this.name != null;
}
#Override
public boolean equals(Object other) {
// base comparison on team name
}
#Override
public int hashCode() {
assert this.name != null;
return name.hashCode();
}
// methods from interface Team:
#Override
public String getName() {
return name;
}
#Override
public Set<Player> getRoster() {
return Collections.unmodifiableSet(new HashSet<>(roster.values()));
}
#Override
public boolean add(Player player) {
return player != null
&& roster.put(player.getName(), player) == null;
}
#Override
public Player find(String name) {
return name == null ? null : roster.get(name);
}
// remove, iterators, etc.
}
I am trying to serialise some POJOs to XML. Some of them use #Transient annotations to indicate that some properties should not be serialised.
I have made a small test case to demonstrate the problem. I have also tried using #XStreamOmit but the result is the same. I do NOT expect to see the HiddenTop property in the output.
The POJO:
package test;
import java.beans.Transient;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
public class DerivedObject
{
private String xVisible = "GOODTOP";
private String xHidden = "BADTOP";
public DerivedObject() {
}
public String getVisibleTop() {
return xVisible;
}
public void setVisibleTop(String xVisible) {
this.xVisible = xVisible;
}
#Transient
public String getHiddenTop() {
return xHidden;
}
#Transient
public void setHiddenTop(String xHidden) {
this.xHidden = xHidden;
}
}
The Main:
package test;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.javabean.JavaBeanConverter;
public class TestAnnotation
{
public static void main(String[] args) {
DerivedObject o = new DerivedObject();
o.setVisibleTop(":-)");
o.setHiddenTop(":-(");
try {
XStream xs = new XStream();
xs.autodetectAnnotations(true);
xs.registerConverter(new JavaBeanConverter(xs.getMapper()),
XStream.PRIORITY_LOW);
System.out.println(xs.toXML(o));
}
catch (Exception e) {
e.printStackTrace();
}
}
}
The output
<test.DerivedObject>
<hiddenTop>:-(</hiddenTop>
<visibleTop>:-)</visibleTop>
</test.DerivedObject>
Becouse JavaBeanProvider doesn't respect the #Transient annotation a solution is to implement you own JavaBeanProvider that respect this annotation:
public class TransientRespectingBeanProvider extends BeanProvider {
#Override
protected boolean canStreamProperty(PropertyDescriptor descriptor) {
final boolean canStream = super.canStreamProperty(descriptor);
if (!canStream) {
return false;
}
final boolean readMethodIsTransient = descriptor.getReadMethod() == null
|| descriptor.getReadMethod().getAnnotation(Transient.class) != null;
final boolean writeMethodIsTransient = descriptor.getWriteMethod() == null
|| descriptor.getWriteMethod().getAnnotation(Transient.class) != null;
final boolean isTransient = readMethodIsTransient
|| writeMethodIsTransient;
return !isTransient;
}
}
You can use it as follows:
final JavaBeanProvider beanProvider = new TransientRespectingBeanProvider();
final Converter converter = new JavaBeanConverter(xstream.getMapper(), beanProvider);
xstream.registerConverter(converter);
In my GWT web application I have a textbox that holds a price.
How can one convert that String to a BigDecimal?
The easiest way is to create new text box widget that inherits ValueBox.
If you do it this way, you won't have to convert any string values manually. the ValueBox takes care of it all.
To get the BigDecimal value entered you can just go:
BigDecimal value = myTextBox.getValue();
Your BigDecimalBox.java:
public class BigDecimalBox extends ValueBox<BigDecimal> {
public BigDecimalBox() {
super(Document.get().createTextInputElement(), BigDecimalRenderer.instance(),
BigDecimalParser.instance());
}
}
Then your BigDecimalRenderer.java
public class BigDecimalRenderer extends AbstractRenderer<BigDecimal> {
private static BigDecimalRenderer INSTANCE;
public static Renderer<BigDecimal> instance() {
if (INSTANCE == null) {
INSTANCE = new BigDecimalRenderer();
}
return INSTANCE;
}
protected BigDecimalRenderer() {
}
public String render(BigDecimal object) {
if (null == object) {
return "";
}
return NumberFormat.getDecimalFormat().format(object);
}
}
And your BigDecimalParser.java
package com.google.gwt.text.client;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.text.shared.Parser;
import java.text.ParseException;
public class BigDecimalParser implements Parser<BigDecimal> {
private static BigDecimalParser INSTANCE;
public static Parser<BigDecimal> instance() {
if (INSTANCE == null) {
INSTANCE = new BigDecimalParser();
}
return INSTANCE;
}
protected BigDecimalParser() {
}
public BigDecimal parse(CharSequence object) throws ParseException {
if ("".equals(object.toString())) {
return null;
}
try {
return new BigDecimal(object.toString());
} catch (NumberFormatException e) {
throw new ParseException(e.getMessage(), 0);
}
}
}
Take a look at GWT-Math.