How to access a singleton and name it in java? - java

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;

Related

Spring aop advice failed to wrapped proxy when the advice bean is in creation

The issue is the same as this question
I am working with the spring aop at annotation aspect, one of my service bean cannot install annotation advice but others can.
Then I debug and found out the reason, the code in BeanFactoryAdvisorRetrievalHelper indicates that if an advice bean is in creation, the serviceBean will failed to install the advisor.
if (this.beanFactory.isCurrentlyInCreation(name))
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
The interceptor is
public class DemoInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//do something
return new Object();
}
}
The advisor config is
config way 1
public class DemoAdvisor implements PointcutAdvisor {
private MethodInterceptor methodInterceptor;
private Pointcut pointcut;
public DemoAdvisor(MethodInterceptor methodInterceptor) {
this.methodInterceptor = methodInterceptor;
this.pointcut = new AnnotationMatchingPointcut(null, DemoAnno.class);
}
#Override
public Advice getAdvice() {
return this.methodInterceptor;
}
#Override
public boolean isPerInstance() {
return true;
}
#Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
#Configuration
public class AnnoAspectConfig {
#Bean
public DemoAdvisor DemoAdvisor() {
DemoAdvisor advisor = new DemoAdvisor(demoInterceptor());
return advisor;
}
#Bean
public DemoInterceptor demoInterceptor() {
DemoInterceptor demoInterceptor = new DemoInterceptor();
return demoInterceptor;
}
}
Then I think it maybe the problem in the advice config, so I change the advice config to the below
config way 2
#Configuration
public class ValidationAdvisor {
#Bean
public DefaultPointcutAdvisor demoAdvisor() {
DemoInterceptor interceptor = new DemoInterceptor();
AnnotationMatchingPointcut annotationMatchingPointcut = AnnotationMatchingPointcut.forMethodAnnotation(DemoAnno.class);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(annotationMatchingPointcut);
advisor.setAdvice(interceptor);
return advisor;
}
}
Then everything goes find, so the question is, why the config way 1 cause the failed of advisor installation while the config way 2 did not?

Export an object with Spring JMX annotations

I'm trying to export some information with Spring JMX annotation driven (I have no xml :D). I have achieved to export Strings and Integer types but I haven't been able to export any object of a class I created.
This is my #Configuration class.
#Configuration
#EnableMBeanExport
#ComponentScan({"my.packages"})
public class AppManager {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppManager.class);
context.refresh();
try {
TimeUnit.MINUTES.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Bean(name = "jmxExporter")
public Exporter jmxExporter() {
return new Exporter();
}
}
This is some class I have with some attributes I want to get.
public class MyClass implements Serializable {
private int param1;
private int param2;
private int param3;
public MyClass() {
// calculate all params
}
public int getParam1() {
return this.param1;
}
public int getParam2() {
return this.param2;
}
public int getParam3() {
return this.param3;
}
}
This is the class that exports it's attributes.
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
#ManagedResource(objectName = "my.packages:type=JMX,name=Exporter")
public class Exporter {
#ManagedAttribute
public String getString() { //This works!
return "Test string";
}
#ManagedAttribute
public MyClass getMyClass() { //This does not work
return new MyClass();
}
}
I need to create MyClass object every time because it has some real-time information that I can't export separately.
In JConsole the value of attribute is "Unavailable".
I'm pretty new to JMX and obviously missing something.
Thank you for your help!
I resolved it by returning CompositeData.
#ManagedAttribute
public CompositeData getMyClass() {
return createCompositeDataForMyClass();
}
I built a CompositeDataSupport for that and it worked.
return new CompositeDataSupport(compositeType, itemNames, itemValues);
Where compositeType is a CompositeType, itemNames is a String[] and itemValues is an Object[].
The CompositeType can be built with something like this
new CompositeType(typeName, typeDescription, itemNames, itemDescriptions, itemTypes);
typeName, typeDescription are Strings. itemNames and itemDescriptions are String[]. itemTypes is an OpenType[]. SimpleType and CompositeType can be used to build OpenType.
All this objects must be imported with
import javax.management.openmbean.*;

java duplicated code in enum

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;
}
}

How to use the #Transient annotation when using JavaBeanConverter in XStream?

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);

How to call parent class objects within a subclass?

I'm not sure if I'm asking this right, as I'm attempting to teach myself Java. I have a class which contains my main method, and within this class are several subclasses that need access to my user settings using java.util.Properties. I have to create the properties object in every subclass in order to make it work, and I can't reference the object using configFilePath, it must be null. I'm wondering if I can create this public object within the parent class, so I don't need to create it in all of its subclasses? Here is my code, I'm really not sure I'm doing this right although it works.
public class Frame1 extends JFrame {
Settings config = new Settings(); //this is the object I want to reference within subclasses
class Update extends SwingWorker<Integer, Void> { //first subclass
#Override
protected Integer doInBackground() throws Exception {
Settings config = new Settings(configFilePath); //yet I have to create the object within every subclass, this time an argument is required.
String templateDir = config.getProperty("templatedir");
String writePath = config.getProperty("outputdir");
//do some logic code, not required for my question
}
#Override
protected void done() {
Update2 update2 = new Update2();
update2.execute(); //start the next subclass which also needs access to Settings(configFilePath)
}
}
}
public class Settings extends JFrame {
String configFilePath = "C:/path/to/settings.properties";
Properties properties = new Properties();
public Settings(String configFilePath) throws IOException {
this.configFilePath = configFilePath;
FileInputStream fis = null;
try {
fis = new FileInputStream(configFilePath);
properties.load(fis);
} catch (FileNotFoundException e) {
setDefaults();
} finally {
if (fis != null) {
fis.close();
}
}
}
}
I'm not sure if I'm doing this right or not, it seems to work but seems to be rather redundant having to create the config object every time I need to access my user settings. I hope this hasn't been asked before, and if it has please link me, as I could not find it.
You can create the Setting class as a Singleton pattern, here is one example:
public class Settings extends JFrame{
String configFilePath = "C:/path/to/settings.properties";
Properties properties = new Properties();
private static Settings instance;
public static Settings getInstance(){
if(instance==null){
instance = new Setting();
}
return instance;
}
private Settings() throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(configFilePath);
properties.load(fis);
} catch (FileNotFoundException e) {
setDefaults();
} finally {
if (fis != null) {
fis.close();
}
}
}
}
Usage in any other class of your system:
Settings.getInstance().getProperty("...");
From Update you can use Frame1.this to access the this of Frame1 (because Update is an inner class of Frame1).
Then to access config you can use Frame1.this.config.
Here is a working example:
public class PrefixerFactory {
private String prefix; // Used by Prefixer
public PrefixerFactory(String prefix) {
this.prefix = prefix;
}
public Prefixer createPrefixer() {
return new Prefixer();
}
public class Prefixer { // Inner class
public String addPrefix(String value) {
// Using "prefix" from PrefixerFactory
return PrefixerFactory.this.prefix + value;
}
}
public static void main(String[] args) {
Prefixer helloPrefixer = new PrefixerFactory("Hello ").createPrefixer();
Prefixer goodbyePrefixer = new PrefixerFactory("Good bye ").createPrefixer();
System.out.println(helloPrefixer.addPrefix("world")); // Hello world
System.out.println(goodbyePrefixer.addPrefix("world")); // Good bye world
}
}

Categories