Ken Y-N Ken Y-N - 7 months ago 30
Java Question

Accessing a @Singleton from an @Entity without using @Inject/@EJB

I'm using Domain-Driven Design (I think!) and I have a requirement to access some global properties. I have my @Singleton thus:

@Singleton
public class MyProperties {
private Properties props;

@PostConstruct
private void initialize()
{
try {
props.load(new FileInputStream("my.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public String getProperty(String propertyName)
{
return props.getProperty(propertyName);
}
}


I would like to do this:

@Entity(name="MYENTITY")
public class MyEntity {
@Inject private MyProperties props;
void doSomething()
{
String myProp = props.getProperty("my-prop");
// ...etc...
}
}


However, this doesn't work -
props
is
null
, and anyway sites tell me not to do that, and I should use a Service Locator instead, but that all smells of using JNDI lookup which EJB 3.x kills off.

My plan might be to try this sort of thing:

@WebListener
public class MyServletContextListener implements ServletContextListener{
@Inject private MyProperties props;
private MyServletContextListener theInstance;

@Override
public void contextInitialized(ServletContextEvent sce) {
theInstance = this;
}

static public MyServletContextListener theInstance() { return theInstance; }
public MyProperties getProperties() { return props; }
}


Does this make sense, or am I barking up the wrong tree, or do I just have some silly bug in my code?

EDIT: Note that I am using vanilla Java EE with CDI, JPA, etc, no Spring.

EDIT2: I see that CDI Best Practises say one should add the @Vetoed annotation to all persistent entities. Currently my application flow control is from a
@MessageBean
through a series of
@Entity
s - is this a design smell?

Answer

Well, I cracked out my venerable Gang of Four book and realised that I have a Visitor pattern here, which is particularly useful as my @Entitys form a hierarchy. So, I will add code like this:

public class DoSomethingVisitor extends EntityVisitor {
    @Inject private MyProperties props;

    @Override
    void visit(MyEntity entity)
    {
        String myProp = props.getProperty("my-prop");
        if(entity.getValue().equals(myProp))
        //...or whatever...
    }
}

And:

@Entity(name="MYENTITY")
public class MyEntity {
    void Accept(EntityVisitor visitor)
    {
        visitor.visit(this);
    }
}

This solution also allows me to get rid of a logger parameter that I was passing around the doSomething() calls, and my business logic is now out of the @Entitys and into a place where I can do injections.

Comments