I have existing model classes that always use builder pattern like this:
public class Model {
public static class Builder {
private boolean isValid;
private List<String> errorMessagesOrNull;
public Builder setIsValid(final boolean isValid) {
this.isValid = isValid;
return this;
}
public Builder setErrorMessages(final List<String> errorMessages) {
this.errorMessagesOrNull = errorMessages;
return this;
}
public List<String> getErrorMessages() {
return this.errorMessagesOrNull == null ? new ArrayList<>() : this.errorMessagesOrNull;
}
public Model Build() {
return new Model(this);
}
}
private boolean isValid;
private List<String> errorMessages;
private Model(final Builder builder) {
this.isValid = builder.isValid;
this.errorMessages = builder.getErrorMessages();
}
public boolean getIsValid() {
return isValid;
}
public List<String> getErrorMessages() {
return errorMessages;
}
}
As you see, the model classes always have isValid and errorMessages. I want to write an abstract class to minimize the repeated logic for those model classes.
So I came up like this abstract class:
public abstract class AbstractModel<T extends AbstractModel<T>> {
public static abstract class Builder<T> {
private boolean isValid;
private List<String> errorMessagesOrNull;
public Builder<T> setIsValid(final boolean isValid) {
this.isValid = isValid;
return this;
}
public Builder<T> setErrorMessages(final List<String> errorMessages) {
this.errorMessagesOrNull = errorMessages;
return this;
}
public List<String> getErrorMessages() {
return this.errorMessagesOrNull == null ? new ArrayList<>() : this.errorMessagesOrNull;
}
public abstract T Build();
}
private boolean isValid;
private List<String> errorMessages;
private AbstractModel(final Builder<T> builder) {
this.isValid = builder.isValid;
this.errorMessages = builder.getErrorMessages();
}
public boolean getIsValid() {
return isValid;
}
public List<String> getErrorMessages() {
return errorMessages;
}
}
But it's not really working as I intended. When I extends the abstract class:
public class Model extends AbstractModel<Model> {
// Empty here since all fields are extended
}
I cannot do something like:
Model model = new Model.Builder.setIsValid(true).Build();
I want the abstract class has Builder static class, so that I don't need to write the static class Builder every time.
Please advise.
You also need to implement the Builder.
public class Model extends AbstractModel<Model>{
private Model(final Builder builder) {
super(builder);
}
public static class Builder2 extends AbstractModel.Builder<Model> {
#Override
public Model Build() {
return new Model(this);
}
}
}
then it possible to call
Model model = new Model.Builder2().Build();
EDIT
Also, the constructor of AbstractBuilder also must be protected.
protected AbstractModel(final Builder<? extends Builder<T>> builder) {
this.isValid = builder.isValid;
this.errorMessages = builder.getErrorMessages();
}
I think that there is a huge flaw in your logic. The program itself doesn't really make any sense at all. Why do you construct a Model with the Builder class in the first place? I think it is better to show you how you should have written your program, instead of just "bodging" it together. Alright, let us start with the Model class.
Let's say the Model class cannot be constructed without a Builder. Would it then make sense to add the Builder class into the Model class? Short answer: no, it wouldn't. Instead, the Builder class should contain the Model class as a non-static internal class.
/**
* The {#code Builder} can construct new instances of the {#code Model} class.
*
* #see Model
*/
public class Builder
{
private final String[] log;
/**
* The {#code Model} class can do something. You can only construct it through a {#code Builder}.
*
* #see Builder
*/
public class Model
{
private final Builder builder;
/**
* Constructs a new {#code Model} with the specified argument.
*
* #param builder the {#code Builder} that constructed the model.
*/
public Model(final Builder builder)
{
this.builder = builder;
}
/**
* Returns the associated {#code Builder}.
*
* #return the builder that constructed the model.
*/
public Builder getBuilder()
{
return this.builder;
}
}
/**
* Constructs a new instance of the {#code Builder} class with the specified argument.
*
* #param log the log of the {#code Builder}.
*/
public Builder(final String... log)
{
this.log = log;
}
/**
* Tries to {#code build} a new instance of the {#code Model} class.
*
* #return the constructed {#code Model}.
*/
public Model build()
{
return new Model(this);
}
/**
* Returns the log of the {#code Builder}.
*
* #return an log.
*/
public String[] getLog()
{
return this.log;
}
/**
* Determines whether or not the {#code Builder} is valid.
*
* #return {#code true} when the specified {#code log} is not {#code null}; {#code false} otherwise.
*/
public boolean isValid()
{
return this.log != null;
}
}
No class other than the Builder can construct a Model. However, if you construct a new instance of the Builder class and get the result of invoking the build method, you'll have access to all public variables and methods.
If you know want to construct a Model, you can do that just like that:
Builder.Model model = new Builder().build();
If you don't want the Builder. prefix, just add an import statement that imports the Model class.
import organisation.projectname.pathToBuilder.Builder.Model;
Related
I plan on writing a query method like
/**
* TODO Auto-generated method documentation
*
* #param entity
* #return EventExecute
*/
#Transactional
#Autowired
public EventExecute save(EventExecute entity) {
String eventKey = entity.getEventKey();
StepDefinitionRepository sdRepository;
List<StepDefinition> stepDefinitions = sdRepository.findByEventKeyAllIgnoreCaseOrderBySequenceAsc(eventKey);
return getEventExecuteRepository().save(entity);
}
I want to lookup the StepDefintions that match an event key.
I tried following the example in the JPA Documentation...
public class SomeClient {
#Autowired
private PersonRepository repository;
public void doSomething() {
List<Person> persons = repository.findByLastname("Matthews");
}
}
But my sdRepository complains that is it not initialized. I found the getStepDefintionRepository() in the ..ServiceImpl.aj but can't call it.
Is there an example out there?
Ok I figured out my error...here is what works.
#Autowired
private StepDefinitionRepository sdRepository;
/**
* Overridden save method to intercept and process the dynamic steps before saving
*
* #param entity
* #return EventExecute
*/
#Transactional
public EventExecute save(EventExecute entity) {
boolean keepGoing = true;
String eventKey = entity.getEventKey();
Set<NameValuePair> messageVariables = null;
String eventArguments = entity.getEventArguments();
List<NameValuePair> eventVariables = null;
if (!eventArguments.isEmpty()){
eventVariables = _ExtractEventVariables(eventArguments);
}
List<StepDefinition> stepDefinitions = sdRepository.findByEventKeyAllIgnoreCaseOrderBySequenceAsc(eventKey);
for (Iterator<StepDefinition> iterator = stepDefinitions.iterator(); iterator.hasNext();) {
I need to Unmarshal XML to Java Object, I have tried with below code. Its create an Object but set all value as a null. code for same:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Dispatch implements java.io.Serializable {
private Integer dispatchId;
private Order order;
/**
* #return the dispatchId
*/
public Integer getDispatchId() {
return dispatchId;
}
/**
* #param dispatchId
* the dispatchId to set
*/
public void setDispatchId(Integer dispatchId) {
this.dispatchId = dispatchId;
}
/**
* #return the order
*/
public Order getOrder() {
return order;
}
/**
* #param order
* the order to set
*/
public void setOrder(Order order) {
this.order = order;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return ""+this.dispatchId;
}
}
I have Dispatch Class with other sub class, i need to convert XML to Java Object. Code for same:
Public class UnmarshalExample {
public static void main(String[] args) {
String xmlString = "<ns1:dispatch xmlns:ns1=\"http://service.order.com\"><ns1:dispatchId>1</ns1:dispatchId><ns1:order><ns1:totalAmount>1000.0</ns1:totalAmount></ns1:order></ns1:dispatch>";
Dispatch dispatch = (Dispatch) JAXB.unmarshal(
new StringReader(xmlString), Dispatch.class);
System.out.println(dispatch);
}
}
As a output it will return null.
Can any one tell me whats wrong thing in my code?
That is odd, I pasted you code and ran and it produces dispatchId 1:
Dispatch class:
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Dispatch implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer dispatchId;
/**
* #return the dispatchId
*/
public Integer getDispatchId() {
return dispatchId;
}
/**
* #param dispatchId
* the dispatchId to set
*/
public void setDispatchId(Integer dispatchId) {
this.dispatchId = dispatchId;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return ""+this.dispatchId;
}
}
Test class
import java.io.*;
import javax.xml.bind.JAXB;
public class Test {
public static void main(String[] args) {
String xmlString = "<ns1:dispatch xmlns:ns1=\"http://service.order.com\"><ns1:dispatchId>1</ns1:dispatchId><ns1:order><ns1:totalAmount>1000.0</ns1:totalAmount></ns1:order></ns1:dispatch>";
Dispatch dispatch = (Dispatch) JAXB.unmarshal(
new StringReader(xmlString), Dispatch.class);
System.out.println(dispatch);
}
}
output is
1
The order is of the type Order. We don't see any code of this class.
This is probably the cause of it as well. You may not provide decent data for the Order to be constructed.
To see how namespaces are used: http://blog.bdoughan.com/2012/11/applying-namespace-during-jaxb-unmarshal.html
I am trying to create a a custom method for use in Pre/Post Authorize calls like this:
public class CustomLSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler{
public CustomSecurityExpressionHandler(){
super();
}
#Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation){
CustomSecurityExpressionRoot root = new CustomSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
return root;
}
}
and
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
private Object target;
public CustomSecurityExpressionRoot(Authentication a) {
super(a);
}
public boolean testDecision(String test){
System.out.println("Printing:"+test+"\n");
return true;
}
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
public Object getFilterObject() {
return filterObject;
}
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
public Object getReturnObject() {
return returnObject;
}
void setThis(Object target) {
this.target = target;
}
public Object getThis() {
return target;
}
public boolean hasPermission(Object permission) {
try {
return super.hasPermission(null, null, permission);
} catch (AccessDeniedException e) {
return false;
}
}
public boolean checkPermission(Object permission) {
return super.hasPermission(null, null, permission);
}
#Override
public boolean hasPermission(Object targetId, String targetType, Object permission) {
try {
return super.hasPermission(targetId, targetType, permission);
} catch (AccessDeniedException e) {
return false;
}
}
public boolean checkPermission(Object targetId, String targetType, Object permission) {
return super.hasPermission(targetId, targetType, permission);
}
#Override
public boolean hasPermission(Object target, Object permission) {
try {
return super.hasPermission(target, permission);
} catch (AccessDeniedException e) {
return false;
}
}
public boolean checkPermission(Object target, Object permission) {
return super.hasPermission(target, permission);
}
}
As seen above I have added the new method testDecision(String), which I can successfully use in my preAuthorize call as below:
#PreAuthorize("testDecision('TestString')")
Event getEvent(int eventId);
But when I call it in the context of a PostAuthorize as:
#PostAuthorize("testDecision('TestString')")
Event getEvent(int eventId);
I get a ClassCastException:
SEVERE: Servlet.service() for servlet [Spring MVC Dispatcher Servlet] in context with path [/myapp] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: com.example.CustomSecurityExpressionRoot cannot be cast to org.springframework.security.access.expression.method.MethodSecurityExpressionRoot] with root cause
java.lang.ClassCastException: com.example.CustomSecurityExpressionRoot cannot be cast to org.springframework.security.access.expression.method.MethodSecurityExpressionRoot
at org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler.setReturnObject(DefaultMethodSecurityExpressionHandler.java:156)
at org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice.after(ExpressionBasedPostInvocationAdvice.java:49)
at org.springframework.security.access.prepost.PostInvocationAdviceProvider.decide(PostInvocationAdviceProvider.java:38)
at org.springframework.security.access.intercept.AfterInvocationProviderManager.decide(AfterInvocationProviderManager.java:73)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.afterInvocation(AbstractSecurityInterceptor.java:282)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:68)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy15.getEvent(Unknown Source)
(..truncated..)
Anyone can help me figure out what I am doing wrong?
It seems you are on an older version of Spring Security. As of Spring Security 3.1.5+ SEC-2245 is fixed & you can create your own expression root and implement MethodSecurityExpressionOperations.
The class CustomSecurityExpressionRoot must extends MethodSecurityExpressionRoot!
(implementing MethodSecurityExpressionOperations) is not enough.
Unfortunately MethodSecurityExpressionRoot is a package protected class.
Therfore you need to put CustomSecurityExpressionRoot in the same package (org.springframework.security.access.expression.method)
or you use the following class as super class for your CustomSecurityExpressionRoot (that is what I do in my projects)
ExtensibleMethodSecurityExpressionRoot:
package org.springframework.security.access.expression.method;
import org.springframework.security.core.Authentication;
/** Makes the class {#link MethodSecurityExpressionRoot} public to other packages. */
public class ExtensibleMethodSecurityExpressionRoot extends MethodSecurityExpressionRoot {
/**
* Instantiates a new extensible method security expression root.
* #param a the Authentication
*/
public ExtensibleMethodSecurityExpressionRoot(final Authentication a) {
super(a);
}
}
My complete way is this:
ExtensibleMethodSecurityExpressionHandler to change the evaluation root context:
package org.springframework.security.access.expression.method;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.DenyAllPermissionEvaluator;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.method.defaultexpression.DefaultMethodSecuritiyExpressionRootFactory;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
/**
* This class is the same like {#link MethodSecurityExpressionHandler} but its evaluation
* root context can be exchanged.
* To use an other evaluation root context, set an other {#link #methodSecurityExpRootFactory}.
*
*/
public class ExtensibleMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {
/** The parameter name discoverer. */
private ParameterNameDiscoverer parameterNameDiscoverer;
/** The permission evaluator. */
private PermissionEvaluator permissionEvaluator;
/** The trust resolver. */
private AuthenticationTrustResolver trustResolver;
/** The expression parser. */
private ExpressionParser expressionParser;
/** The method security expression root factory. */
private MethodSecurityExpressionRootFactory<?> methodSecurityExpRootFactory;
/** The role hierarchy. */
private RoleHierarchy roleHierarchy;
/**
* Instantiates a new extensible method security expression handler.
*/
public ExtensibleMethodSecurityExpressionHandler() {
this.parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
this.permissionEvaluator = new DenyAllPermissionEvaluator();
this.trustResolver = new AuthenticationTrustResolverImpl();
this.expressionParser = new SpelExpressionParser();
this.methodSecurityExpRootFactory = new DefaultMethodSecuritiyExpressionRootFactory();
}
/**
* Uses a {#link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation and
* configures it with a {#link MethodSecurityExpressionRoot} instance as the expression root object.
*
* #param auth the auth
* #param mi the mi
* #return the evaluation context
*/
#Override
public EvaluationContext createEvaluationContext(final Authentication auth, final MethodInvocation mi) {
MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth,
mi,
this.parameterNameDiscoverer);
MethodSecurityExpressionRoot root = this.methodSecurityExpRootFactory.createMethodSecurityExpressionRoot(auth);
root.setTrustResolver(this.trustResolver);
root.setPermissionEvaluator(this.permissionEvaluator);
root.setRoleHierarchy(this.roleHierarchy);
ctx.setRootObject(root);
return ctx;
}
/*
* (non-Javadoc)
*
* #see
* org.springframework.security.access.expression.method.MethodSecurityExpressionHandler#filter(java.lang.Object,
* org.springframework.expression.Expression, org.springframework.expression.EvaluationContext)
*/
#Override
#SuppressWarnings({ "unchecked", "rawtypes" })
public Object filter(final Object filterTarget, final Expression filterExpression, final EvaluationContext ctx) {
MethodSecurityExpressionRoot rootObject = (MethodSecurityExpressionRoot) ctx.getRootObject().getValue();
List retainList;
if (filterTarget instanceof Collection) {
Collection collection = (Collection) filterTarget;
retainList = new ArrayList(collection.size());
for (Object filterObject : (Collection) filterTarget) {
rootObject.setFilterObject(filterObject);
if (ExpressionUtils.evaluateAsBoolean(filterExpression, ctx)) {
retainList.add(filterObject);
}
}
collection.clear();
collection.addAll(retainList);
return filterTarget;
}
if (filterTarget.getClass().isArray()) {
Object[] array = (Object[]) filterTarget;
retainList = new ArrayList(array.length);
for (Object element : array) {
rootObject.setFilterObject(element);
if (ExpressionUtils.evaluateAsBoolean(filterExpression, ctx)) {
retainList.add(element);
}
}
Object[] filtered = (Object[]) Array.newInstance(filterTarget.getClass().getComponentType(),
retainList.size());
for (int i = 0; i < retainList.size(); i++) {
filtered[i] = retainList.get(i);
}
return filtered;
}
throw new IllegalArgumentException("Filter target must be a collection or array type, but was " + filterTarget);
}
/*
* (non-Javadoc)
*
* #see org.springframework.security.access.expression.method.MethodSecurityExpressionHandler#getExpressionParser()
*/
#Override
public ExpressionParser getExpressionParser() {
return this.expressionParser;
}
/**
* Sets the parameter name discoverer.
*
* #param parameterNameDiscoverer the new parameter name discoverer
*/
public void setParameterNameDiscoverer(final ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
/**
* Sets the permission evaluator.
*
* #param permissionEvaluator the new permission evaluator
*/
public void setPermissionEvaluator(final PermissionEvaluator permissionEvaluator) {
this.permissionEvaluator = permissionEvaluator;
}
/**
* Sets the trust resolver.
*
* #param trustResolver the new trust resolver
*/
public void setTrustResolver(final AuthenticationTrustResolver trustResolver) {
this.trustResolver = trustResolver;
}
/*
* (non-Javadoc)
*
* #see
* org.springframework.security.access.expression.method.MethodSecurityExpressionHandler#setReturnObject(java.lang
* .Object, org.springframework.expression.EvaluationContext)
*/
#Override
public void setReturnObject(final Object returnObject, final EvaluationContext ctx) {
((MethodSecurityExpressionRoot) ctx.getRootObject().getValue()).setReturnObject(returnObject);
}
/**
* Sets the role hierarchy.
*
* #param roleHierarchy the new role hierarchy
*/
public void setRoleHierarchy(final RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy;
}
/**
* Gets the method security expression root factory.
*
* #return the method security expression root factory
*/
public MethodSecurityExpressionRootFactory<?> getMethodSecurityExpressionRootFactory() {
return this.methodSecurityExpRootFactory;
}
/**
* Sets the method security expression root factory.
*
* #param methodSecurityExpressionRootFactory the new method security expression root factory
*/
public void setMethodSecurityExpressionRootFactory(
final MethodSecurityExpressionRootFactory<?> methodSecurityExpressionRootFactory) {
this.methodSecurityExpRootFactory = methodSecurityExpressionRootFactory;
}
/**
* Gets the parameter name discoverer.
*
* #return the parameter name discoverer
*/
public ParameterNameDiscoverer getParameterNameDiscoverer() {
return this.parameterNameDiscoverer;
}
/**
* Gets the permission evaluator.
*
* #return the permission evaluator
*/
public PermissionEvaluator getPermissionEvaluator() {
return this.permissionEvaluator;
}
/**
* Gets the trust resolver.
*
* #return the trust resolver
*/
public AuthenticationTrustResolver getTrustResolver() {
return this.trustResolver;
}
/**
* Gets the role hierarchy.
*
* #return the role hierarchy
*/
public RoleHierarchy getRoleHierarchy() {
return this.roleHierarchy;
}
/**
* Sets the expression parser.
*
* #param expressionParser the new expression parser
*/
public void setExpressionParser(final ExpressionParser expressionParser) {
this.expressionParser = expressionParser;
}
}
MethodSecurityExpressionRootFactory:
package org.springframework.security.access.expression.method;
import org.springframework.security.core.Authentication;
/**
* Factory Class/Template Class-Pattern: Template Class interface to create different expression root objects.
*
* #param <T> the {#link ExtensibleMethodSecurityExpressionRoot} created by this factory.
*/
public interface MethodSecurityExpressionRootFactory<T extends ExtensibleMethodSecurityExpressionRoot> {
/**
* Creates a new MethodSecurityExpressionRoot object.
*
* #param authentication the authentication
* #return the extensible method security expression root
*/
T createMethodSecurityExpressionRoot(final Authentication authentication);
}
DefaultMethodSecuritiyExpressionRootFactory: only needed if one want to use the ExtensibleMethodSecurityExpression handler without own extension
package org.springframework.security.access.expression.method.defaultexpression;
import org.springframework.security.access.expression.method.ExtensibleMethodSecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionRootFactory;
import org.springframework.security.core.Authentication;
/**
* Create the default {#link ExtensibleMethodSecurityExpressionRoot} expression root.
*/
public class DefaultMethodSecuritiyExpressionRootFactory implements
MethodSecurityExpressionRootFactory<ExtensibleMethodSecurityExpressionRoot> {
#Override
public ExtensibleMethodSecurityExpressionRoot createMethodSecurityExpressionRoot(final Authentication auth) {
return new ExtensibleMethodSecurityExpressionRoot(auth);
}
}
Example Customized Method Expression Root
package com.queomedia.vwcotool.infrastructure.security.spring;
import org.springframework.security.access.expression.method.ExtensibleMethodSecurityExpressionRoot;
import org.springframework.security.core.Authentication;
public class VwCoToolMethodSecurityExpressionRoot extends ExtensibleMethodSecurityExpressionRoot {
private Authentication a;
public MyMethodSecurityExpressionRoot(final Authentication a) {
super(a);
this.a = a;
}
public isXXX(final DomainObject x){
return x.getCreator().getName().equals(a.getPrincipal());
}
}
I'm developing computer vision application and I will need Classifier class. This class will be immutable per run of application and it loads the trained data from disk on initialization. I want to ensure that whole program will have access to same trained data and I want to block reloading the from disk once they are loaded.
What I was considering was to use either static class or singleton. I'm not sure how to load data to static class, because the path to data file is not know at compile time - it will be program argument. So I was thinking of Singleton pattern, but there I don't know how to initialize it dynamically.
My idea was to use following:
class Singleton {
private static Singleton instance;
private Singleton() { ... }
private static SomeDataObject data;
public static Singleton getInstance() {
if(instance == null)
instance = new Singleton();
return instance;
}
public static init(string dataPath){
if(data == null)
loadDataFromFile(dataPath)
}
}
This would not work, because I have no control which method will be called first.
I know the proper way would be to create the instance with data at the begining and pass it to all classes and methods which need it, but that's not really general solution. I can keep track of all calls to Classifier in my own code, but if I would make the code as API, this would be a problem.
In short how to initialize singleton at runtime?
I don't think (exactly) what you want to do would work.
The below would work:
public static void main(String[] args)
{
Singleton.init("somepath");
...
Singleton.getInstance().doingStuff();
...
}
A better implementation may be: (which would cause a NullPointerException if you try to use it without calling init first) (not really Singleton any more though)
private static Singleton instance;
private SomeDataObject data;
private Singleton(String path) { loadDataFromFile(path); ... }
public static Singleton getInstance() {
return instance;
}
public static void init(String dataPath){
instance = new Singleton(dataPath);
}
Then there's: (possible bad coding practice aside)
class Main
{
public static void main(String[] args)
{
Singleton.currentPath = "somepath";
...
}
}
class Singleton
{
public static String currentPath = null;
private static Singleton instance;
private SomeDataObject data;
private Singleton(String path) { loadDataFromFile(path); ... }
public static Singleton getInstance() {
if(instance == null && currentPath != null)
instance = new Singleton(currentPath);
return instance;
}
}
which I suppose doesn't really solve much.
I use something that is "more" threadsafe than the current winning solution with almost no synchronized used.
import java.util.function.Supplier;
public class InitOnce {
/**
* Marked as final to prevent JIT reordering
*/
private final Supplier<String> theArgs;
private InitOnce(Supplier<String> supplier) {
super();
this.theArgs = supplier;
}
/**
* Uses the arguments to do something
*
* #return
*/
public String doSomething() {
return "Something : " + theArgs.get();
}
/**
* Initializes all the things
*
* #param someArgs
*/
public static synchronized void init(final Supplier<String> someArgs) {
class InitOnceFactory implements Supplier<InitOnce> {
private final InitOnce initOnceInstance = new InitOnce(someArgs);
#Override
public InitOnce get() {
return initOnceInstance;
}
}
if (!InitOnceFactory.class.isInstance(instance)) {
instance = new InitOnceFactory();
} else {
throw new IllegalStateException("Already Initialized");
}
}
private static Supplier<InitOnce> instance = new InitOnceHolder();
/**
* Temp Placeholder supplier
*
*/
private static final class InitOnceHolder implements Supplier<InitOnce> {
#Override
public synchronized InitOnce get() {
if (InitOnceHolder.class.isInstance(instance))
throw new IllegalStateException("Not Initialized");
return instance.get();
}
}
/**
* Returns the instance
*
* #return
*/
public static final InitOnce getInstance() {
return instance.get();
}
}
java.util.Collections has several unmodifiable methods that provide unmodifiable collection views by wrapping collections in decorators that prohibit mutation operations.
Java 6 added support for java.util.NavigableSet and java.util.NavigableMap.
I'd like to be able to have unmodifiable NavigableSets and NavigableMaps, but java.util.Collections#unmodifiableSortedSet(SortedSet) and java.util.Collections#unmodifiableSortedMap(SortedMap) are not sufficient because they do not support the operations that are particular to NavigableSet and NavigableMap.
Are there de-facto implementations for unmodifiableNavigableSet and unmodifiableNavigableMap?
Guava now provides (since version 12.0, released April 30, 2012) Maps.unmodifiableNavigableMap and Sets.unmodifiableNavigableSet.
Java SE 8 included these two methods.
See the Javadoc.
This is just a guess, but part of the reason why an unmodifiable implementation was not provided may be due to the fact that the NavigableSet/Map interfaces expose mutating methods that aren't marked as optional:
NavigableSet.pollFirst
NavigableSet.pollLast
NavigableMap.pollFirstEntry
NavigableMap.pollLastEntry
That said, it seems reasonable when providing an unmodifiable implementation to just throw an UnsupportedOperationException. That is what is done in these implementations (which assume you're using GoogleGuava):
NavigableSet:
import static java.util.Collections.unmodifiableSortedSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.SortedSet;
import com.google.common.collect.ForwardingSortedSet;
/**
* {#link NavigableSet} equivalent of {#link Collections#unmodifiableSortedSet(SortedSet)}.
* This is unfortunately needed because {#link Collections} lacks "UnmodifiableNavigableSet"
* (see http://stackoverflow.com/questions/2577706/unmodifiable-navigableset-navigablemap-in-java
* and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6907251).
*
* This is just a guess, but part of the reason why an unmodifiable implementation was not provided may be due to the fact that
* {#link NavigableSet} exposes mutating methods that aren't marked as optional:
* - {#link NavigableSet#pollFirst()}
* - {#link NavigableSet#pollLast()}
*
* In addition, one can't go the immutable route, as Google Guava doesn't provide an Immutable variant
* (see http://code.google.com/p/guava-libraries/issues/detail?id=664).
*
* #param <E> See {#link NavigableSet}
*/
public final class UnmodifiableNavigableSet<E> extends ForwardingSortedSet<E> implements NavigableSet<E> {
private final NavigableSet<E> delegate;
private final SortedSet<E> unmodifiableDelegate;
/**
* #param delegate See {#link ForwardingSortedSet#delegate()}.
*/
public UnmodifiableNavigableSet(NavigableSet<E> delegate) {
this.delegate = delegate;
unmodifiableDelegate = unmodifiableSortedSet(delegate);
}
/**
* #param delegate
* #return {#link #UnmodifiableNavigableSet(NavigableSet)}
* #see EffectiveJava#Static_factories_instead_of_constructors
*/
public static <E> UnmodifiableNavigableSet<E> newUnmodifiableNavigableSet(NavigableSet<E> delegate) {
return new UnmodifiableNavigableSet<E>(delegate);
}
#Override
protected SortedSet<E> delegate() {
return unmodifiableDelegate;
}
#Override
public E ceiling(E e) {
return delegate.ceiling(e);
}
#Override
public Iterator<E> descendingIterator() {
// NavigableSet.descendingIterator explicitly states this behavior.
// By doing this, we don't need to do anything extra to ensure the iterator is unmodifiable.
return descendingSet().iterator();
}
#Override
public NavigableSet<E> descendingSet() {
return newUnmodifiableNavigableSet(delegate.descendingSet());
}
#Override
public E floor(E e) {
return delegate.floor(e);
}
#Override
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
return newUnmodifiableNavigableSet(delegate.headSet(toElement, inclusive));
}
#Override
public E higher(E e) {
return delegate.higher(e);
}
#Override
public E lower(E e) {
return delegate.lower(e);
}
#Override
public E pollFirst() {
throw new UnsupportedOperationException();
}
#Override
public E pollLast() {
throw new UnsupportedOperationException();
}
#Override
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
return newUnmodifiableNavigableSet(delegate.subSet(fromElement, fromInclusive, toElement, toInclusive));
}
#Override
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
return newUnmodifiableNavigableSet(delegate.tailSet(fromElement, inclusive));
}
}
NavigableMap:
import static UnmodifiableNavigableSet.newUnmodifiableNavigableSet;
import static java.util.Collections.unmodifiableSortedMap;
import java.util.AbstractMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.SortedMap;
import com.google.common.collect.ForwardingSortedMap;
/**
* This class has the same rational as {#link UnmodifiableNavigableSet}.
* #param <K> See {#link NavigableMap}
* #param <V> See {#link NavigableMap}
*/
public final class UnmodifiableNavigableMap<K,V> extends ForwardingSortedMap<K,V> implements NavigableMap<K,V> {
private final NavigableMap<K,V> delegate;
private final SortedMap<K,V> unmodifiableDelegate;
/**
* #param delegate See {#link ForwardingSortedMap#delegate()}.
*/
public UnmodifiableNavigableMap(NavigableMap<K,V> delegate) {
this.delegate = delegate;
unmodifiableDelegate = unmodifiableSortedMap(delegate);
}
/**
* #param delegate
* #return {#link #UnmodifiableNavigableMap(NavigableMap)}
* #see EffectiveJava#Static_factories_instead_of_constructors
*/
public static <K,V> UnmodifiableNavigableMap<K,V> newUnmodifiableNavigableMap(NavigableMap<K,V> delegate) {
return new UnmodifiableNavigableMap<K,V>(delegate);
}
#Override
protected SortedMap<K,V> delegate() {
return unmodifiableDelegate;
}
private Map.Entry<K,V> newImmutableEntry(Map.Entry<K,V> entry) {
return entry == null ? null : new AbstractMap.SimpleImmutableEntry<K,V>(entry);
}
#Override
public Map.Entry<K,V> ceilingEntry(K key) {
return newImmutableEntry(delegate.ceilingEntry(key));
}
#Override
public K ceilingKey(K key) {
return delegate.ceilingKey(key);
}
#Override
public NavigableSet<K> descendingKeySet() {
return newUnmodifiableNavigableSet(delegate.descendingKeySet());
}
#Override
public NavigableMap<K,V> descendingMap() {
return newUnmodifiableNavigableMap(delegate.descendingMap());
}
#Override
public Map.Entry<K,V> firstEntry() {
return newImmutableEntry(delegate.firstEntry());
}
#Override
public Map.Entry<K,V> floorEntry(K key) {
return newImmutableEntry(delegate.floorEntry(key));
}
#Override
public K floorKey(K key) {
return delegate.floorKey(key);
}
#Override
public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
return newUnmodifiableNavigableMap(delegate.headMap(toKey, inclusive));
}
#Override
public Map.Entry<K,V> higherEntry(K key) {
return newImmutableEntry(delegate.higherEntry(key));
}
#Override
public K higherKey(K key) {
return delegate.higherKey(key);
}
#Override
public Map.Entry<K,V> lastEntry() {
return newImmutableEntry(delegate.lastEntry());
}
#Override
public Map.Entry<K,V> lowerEntry(K key) {
return newImmutableEntry(delegate.lowerEntry(key));
}
#Override
public K lowerKey(K key) {
return delegate.lowerKey(key);
}
#Override
public NavigableSet<K> navigableKeySet() {
return newUnmodifiableNavigableSet(delegate.navigableKeySet());
}
#Override
public Map.Entry<K,V> pollFirstEntry() {
throw new UnsupportedOperationException();
}
#Override
public Map.Entry<K,V> pollLastEntry() {
throw new UnsupportedOperationException();
}
#Override
public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
return newUnmodifiableNavigableMap(delegate.subMap(fromKey, fromInclusive, toKey, toInclusive));
}
#Override
public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
return newUnmodifiableNavigableMap(delegate.tailMap(fromKey, inclusive));
}
}
From Christian Semrau (in the question comments):
There are no such methods within the JDK, as mentioned in this bug report.