How to fill #EJB annotated fields programmatically via glassfish container? - servlets

I have a following problem. I have defined an interface:
#Local
public interface ProductTypeLister {
Collection<ListElement> getList();
}
Also, I have defined an implementation for this thing:
#Stateless(name = "ProductTypeLister")
#Local(ProductTypeLister.class)
public class ProductTypeListerImpl implements ProductTypeLister {
#Override
public Collection<ListElement> getList() {
// Implementation code
}
}
And now I want to use it via annotation:
public class ListProductTypeAction extends ActionHandler {
#EJB
protected ProductTypeLister lister;
#Override
public String execute(HttpServletRequest request) throws ServletException {
request.setAttribute("list", lister.getList());
return "listPage.jsp";
}
}
But I get the NullPointerException, since lister is not filled. Now, the problem is, that ActionHandler is not a derivative of HttpServlet and is not executed by the container itself. Instead, we are using FrontController patter - i.e. there is one servlet that handles all the incoming messages and creates required handlers via a simple construction. And therefore the EJB annotated fields are not filled automatically. However, I can fill this specific case in the following manner:
public ListProductTypeAction() throws NamingException {
InitialContext context = new InitialContext();
lister = (ProductTypeLister) context.lookup("<PATH>/ProductTypeLister");
}
In that case everything works fine, but this means I have to do for every handler the specified lookup with JNDI help, but all I want is to get it with annotation help. Therefore, the main servlet needs the following method:
private void fillHandler(ActionHandler handler) {
// Fill #EJB annotated fields
}
But how can I fill it? Of course, I can manually run through every field and check if it's annotated EJB and fill it using JNDI based on the interface unqualified name. But is there a way to do this using the libraries I already have? After all, Glassfish is supposed to fill those fields during the deployment phase. How can I make him do that for a non-servlet class?

J2EE tutorial
Dependency injection is the simplest way of obtaining an enterprise bean reference. Clients that run within a Java EE server-managed environment,
JavaServer Faces web applications, JAX-RS web services, other
enterprise beans, or Java EE application clients, support dependency
injection using the javax.ejb.EJB annotation.
Applications that run outside a Java EE server-managed environment,
such as Java SE applications, must perform an explicit lookup. JNDI
supports a global syntax for identifying Java EE components to
simplify this explicit lookup.
So even if your class is inside a J2EE container, but its lifecycle is not managed by container, you are out of luck, you have to do it manually.

Related

springboot+mybatis, About Native Dao development

I'm trying a new development method.
In mybatis3, I write mapper.java and mapper.xml usually.
I know, the sql statements is corresponded by sqlId(namespace+id).
I want to execute the sql statement like this :
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
but I get a error:
Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.JinBoot.test
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at cn.tianyustudio.jinboot.dao.BaseDao.select(BaseDao.java:20)
at cn.tianyustudio.jinboot.service.BaseService.select(BaseService.java:10)
at cn.tianyustudio.jinboot.controller.BaseController.test(BaseController.java:21)
here is my BaseDao.java
public class BaseDao {
private static SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
public static List<Map> select(String sqlId, Map param) {
try {
factoryBean.setDataSource(new DruidDataSource());
SqlSessionFactory sessionFactory = factoryBean.getObject();
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
here is UserMapper.xml
<mapper namespace="mapper.JinBoot">
<select id="test" parameterType="hashMap" resultType="hashMap">
select * from user
</select>
</mapper>
the application.properties
mybatis.mapperLocations=classpath:mapper/*.xml
I start the project, the send a http request, after controller and service ,the param 'sqlId' in BaseDao is 'mapper.JinBoot.test' (see error info).
In method 'BaseDao.select', both the parameter and the result type is Map.
So I don't want to create UserMapper.java, I want try it.
How can I resolve it? What's the malpractice of this way?
This does not work because spring boot creates its own SqlSessionFactory. And the option in application.properties that specifies where mappers should be looked for is only set for that SqlSessionFactory. You are creating unrelated session factory in your DAO and it does not know where to load mappers definition.
If you want to make it work you need that you DAO is spring managed so that you can inject mybatis session factory into it and use it in select. This would also require that you convert select into non static method.
As I understand you want to have only one method in you base DAO class and use it in individual specific DAO classes. I would say it makes little sense. If the method returns Map there will be some place that actually maps this generic type to some application specific types. This would probably be in the child DAOs. So you still need to create the API of the child DAO with the signature that uses some input parameters and returns some domain objects. And that's exactly what you want to avoid by not creating mybatis mapper classes.
The thing is that you can treat your mytabis mappers as DAOs. That is you mappers would be your DAOs. And you don't need another layer. As I understand now you have two separate layers - DAO and mappers and you want to remove boilerplate code. I think it is better to remove DAO classes. They are real boilerplate and mybatis mapper can serve as DAO perfectly. You inject it directly to you service and service depends only on the mapper class. The logic of the mapping is in the mapper xml file. See also answer to this question Can Spring DAO be merged into Service layer?

ASP.NET Core Dependency Injection with Multiple Constructors

I have a tag helper with multiple constructors in my ASP.NET Core application. This causes the following error at runtime when ASP.NET 5 tries to resolve the type:
InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'MyNameSpace.MyTagHelper'. There should only be one applicable constructor.
One of the constructors is parameterless and the other has some arguments whose parameters are not registered types. I would like it to use the parameterless constructor.
Is there some way to get the ASP.NET 5 dependency injection framework to select a particular constructor? Usually this is done through the use of an attribute but I can't find anything.
My use case is that I'm trying to create a single class that is both a TagHelper, as well as a HTML helper which is totally possible if this problem is solved.
Apply the ActivatorUtilitiesConstructorAttribute to the constructor that you want to be used by DI:
[ActivatorUtilitiesConstructor]
public MyClass(ICustomDependency d)
{
}
This requires using the ActivatorUtilities class to create your MyClass. As of .NET Core 3.1 the Microsoft dependency injection framework internally uses ActivatorUtilities; in older versions you need to manually use it:
services.AddScoped(sp => ActivatorUtilities.CreateInstance<MyClass>(sp));
Illya is right: the built-in resolver doesn't support types exposing multiple constructors... but nothing prevents you from registering a delegate to support this scenario:
services.AddScoped<IService>(provider => {
var dependency = provider.GetRequiredService<IDependency>();
// You can select the constructor you want here.
return new Service(dependency, "my string parameter");
});
Note: support for multiple constructors was added in later versions, as indicated in the other answers. Now, the DI stack will happily choose the constructor with the most parameters it can resolve. For instance, if you have 2 constructors - one with 3 parameters pointing to services and another one with 4 - it will prefer the one with 4 parameters.
ASP.NET Core 1.0 Answer
The other answers are still true for parameter-less constructors i.e. if you have a class with a parameter-less constructor and a constructor with arguments, the exception in the question will be thrown.
If you have two constructors with arguments, the behaviour is to use the first matching constructor where the parameters are known. You can look at the source code for the ConstructorMatcher class for details here.
ASP.NET Core Answer
I've ended up with the following workaround until they fix/improve this.
First, declare only one constructor in your controller (passing your required configuration settings only), considering that the settings objects passed in the constructor can be null (.NET Core will inject them automatically if you configure them in the Startup method):
public class MyController : Controller
{
public IDependencyService Service { get; set; }
public MyController(IOptions<MySettings> settings)
{
if (settings!= null && settings.Value != null)
{
Service = new DependencyServiceImpl(settings.Value);
}
}
}
Then, in your tests methods you can instantiate the controller in two ways:
Mocking the IOptions object when you construct the tested object
Construct passing null in all parameters and then Stub the dependency that you will use in your tests. Following you have an example:
[TestClass]
public class MyControllerTests
{
Service.Controllers.MyController controller;
Mock<IDependencyService> _serviceStub;
[TestInitialize]
public void Initialize()
{
_serviceStub = new Mock<IDependencyService>();
controller = new Service.Controllers.MyController(null);
controller.Service = _serviceStub.Object;
}
}
From this point you can have full testing with dependency injection and mocking ready in .NET Core.
Hope it helps
Azure Functions .NET 7 Isolated
Building on Kévin Chalet answer, if you're using azure functions issolated, you can call the GetService function.
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(s => {
s.AddHttpClient();
s.AddSingleton<DataLookup>(l => {
var dependency = l.GetService<IHttpClientFactory>();
return new DataLookup(dependency);
});
})
.Build();

Using Twitter4J's UserStreamListener with EJB

Looking around StackOverflow, I see this answer to a similar problem - according to the Twitter4J documentation, TwitterStream#addListener takes a callback function. I have naively written my class as follows:
#Stateless
#LocalBean
public class TwitterListenerThread implements Runnable {
private TwitterStream twitterStream;
public TwitterListenerThread(){}
#EJB private TwitterDispatcher dispatcher;
#Override
public void run() {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setJSONStoreEnabled(true)
.setOAuthConsumerKey(Properties.getProperty("twitter_OAuthConsumerKey"))
.setOAuthConsumerSecret(Properties.getProperty("twitter_OAuthConsumerSecret"))
.setOAuthAccessToken(Properties.getProperty("twitter_OAuthAccessToken"))
.setOAuthAccessTokenSecret(Properties.getProperty("twitter_OAuthAccessTokenSecret"));
twitterStream = new TwitterStreamFactory(cb.build()).getInstance();
UserStreamListener listener = new UserStreamListener() {
#Override
public void onStatus(Status status) {
dispatcher.dispatch(status);
}
// Standard code
};
twitterStream.addListener(listener);
// Listen for all user activity
String user = Properties.getProperty("twitter-userid");
String[] users = {user};
twitterStream.user(users);
}
}
Now, on my colleague's PC this soon fails with an attempt to invoke when container is undeployed on the dispatcher.dispatch(status); line. I understand the reason as being due to the Twitter4J threading model not playing well with the JavaEE EJB model, but I cannot work out what to do based on the answer presented in the linked answer - how would I use a Message-Driven Bean to listen in to the Twitter stream?
After a little thinking, I worked out that the solution offered was to write a separate application that used just Java SE code to feed, using non-annotated code, a JMS queue with tweets, and then in my main application use a Message-Driven Bean to listen to the queue.
However, I was not satisfied with that work-around, so I searched a little more, and found Issue TFJ-285, Allow for alternative implementations of Dispatcher classes:
Now it is possible to introduce your own dispatcher implementation.
It can be Quartz based, it can be MDB based, and it can be EJB-timer based.
By default, Twitter4J still uses traditional and transient thread based dispatcher.
Implement a class implementing twtitter4j.internal.async.Dispatcher interface
put the class in the classpath
set -Dtwitter4j.async.dispatcherImpl to locate your dispatcher implementation
This is the default implementation on GitHub, so one could replace the:
private final ExecutorService executorService;
with a:
private final ManagedExecutorService executorService;
And, in theory, Bob's your uncle. If I ever get this working, I shall post the code here.

Failure of singleton EJB injection in Vaadin application

iI'm playing around with the Charts and CDI add-ons for Vaadin at the moment and am trying to inject a mock data source into a Chart class. The data source is a singleton bean that has already had a reference injected into the View that will be displaying the chart but I was under the impression that this shouldn't matter as singletons are application scoped.
The EJB is injected correctly into the view but when the chart class is instantiated, the injection of the data source fails and returns a null reference. I've been using the no-interface facility up until now but even if I do use an interface for the data source, this doesn't make any difference. I'm guessing that there is either a scoping issue or I'm fundamentally misusing/misunderstanding CDI. The other possibility is that I've run into a limitation to the Vaadin CDI add-on as this methodology worked without problems in JSF2.2.
If anyone has any ideas or pointers I'd be really grateful as it's pretty frustrating. Granted this is a quick and dirty implementation but it is a prototype; refactoring to separate concerns (data provision vs building UI components) may well sort the issue but I'd like to understand what's happening here first.
EJB:
#Startup
#Singleton
public class MockDataProvider implements Serializable {
private static final long serialVersionUID = -4789949304830373309L;
private Random rand = new Random();
private Collection<Person> people = new ArrayList<Person>();
private Collection<Address> addresses = new ArrayList<Address>();
private Collection<Evnt> evnts = new ArrayList<Evnt>();
private Collection<TicketType> tickets = new ArrayList<TicketType>();
/**
* Initialize the data for the application
*/
public MockDataProvider() {
}
#PostConstruct
private void init() {
loadAddressData();
loadTicketData();
loadEventData();
loadPersonData();
}
View implementation (injection successful here):
#CDIView(DashboardView.VIEW_ID)
public class DashboardView extends AbstractMVPView implements IDashboardView {
public final static String VIEW_ID = "dashboard";
#Inject
#CDILogger
private Logger logger;
#EJB
MockDataProvider dataProvider;
#Inject
EventsPerMonthChart eventsPerMonthChart;
private Table eventsTable;
private Table peopleTable;
public DashboardView() {
}
Chart class (implemented by DashboardView - EJB injection fails so a null pointer exception is thrown by dataProvider.getEvntCollection.
#Dependent
public class EventsPerMonthChart extends Chart {
#EJB
MockDataProvider dataProvider;
public EventsPerMonthChart() {
super(ChartType.PIE);
setCaption("Events per month");
getConfiguration().setTitle("");
getConfiguration().getChart().setType(ChartType.PIE);
setWidth("100%");
setHeight("90%");
DataSeries series = new DataSeries();
ArrayList<Evnt> events = (ArrayList) dataProvider.getEvntCollection();
OK - it looks like the problem was down to ignorance on my part as I did not understand the contexts where EJB injection is permitted.
The EJB (MockDataProvider) is instantiated by the container and injected into the DashboardView class which, as it was annotated with #CDIView, is also managed by the container. Hence, everything works fine. However, the Chart object was not container managed (despite my misguided addition of #Dependent to try and get the container to "notice" it) - injection into POJOs is not permitted but appears to fail silently which only added to my confusion.
Granted, the code structure is pretty appalling (close coupling, highly dependant and no separation of concerns) and this shoddy approach to prototyping has been responsible for creating the issue. Passing the Charts object the data directly or a via reference to the EJB via a constructor call works without problems.
Good job your learn from your mistakes. At the rate I'm making them, I'm going to be a genius!

Using IOC Container for multiple concrete types

I want to implement IOC in my application but i am confused, in my application i have multiple concrete classes which implement an interface. Consider this scenario:-
I have an Inteface ICommand and following concrete types which implement this interface:-
AddAddress
AddContact
RemoveAddress
RemoveContact
Basically user performs all this action in UI and then List is passed to the service layer where each command is executed.
So in GUI layer I will write
ICommand command1 = new AddAddress();
ICommand command2 = new RemoveContact();
In command manger
List<ICommand> listOfCommands = List<ICommand>();
listOfCommands.Add(command1);
listOfCommands.Add(command2);
Then finally will pass listOfCommands to service layer.
Now as per my understanding of IOC is only one concrete class is mapped to the interface. And we use this syntax to get our concrete type from StructureMap container.
ICommand command = ObjectFactory.GetInstance<ICommand>();
How should i implement IOC in this scenario?
In this scenario you're better off making your commands into value objects, i.e. not created by the IoC container:
class AddAddressCommand {
public AddAddressCommand(string address) {
Address = address;
}
public string Address { get; private set; }
}
When you create a command, you really do want a specific implementation, and you want to parameterise it precisely, both concerns that will work against the services of the IoC container. This will become even more relevant if you decide at some point to serialize the command objects.
Instead, make the service-layer components that execute the commands into IoC-provided components:
class AddAddressHandler : IHandler<AddAddressCommand> {
public AddAddressHandler(ISomeDependency someDependency) { ... }
public void Handle(AddAddressCommand command) {
// Execution logic using dependencies goes here
}
}
In your case, the component that accepts the list of commands to execute will need to resolve the appropriate handler for each command and dispatch the command object to it.
There's some discussion of how to do this with Windsor here: http://devlicious.com/blogs/krzysztof_kozmic/archive/2010/03/11/advanced-castle-windsor-generic-typed-factories-auto-release-and-more.aspx - the community supporting your IoC container of choice will be able to help you with its configuration.
As mentioned by Mark, StructureMap will allow you to set up and call named instances of an interface:
ObjectFactory.Initialize(x =>
{
x.For<ISomeInterface>().Add<SomeImplementation>().Named("SomeName");
}
You can still add a default instance for that particular interface, of course:
ObjectFactory.Initialize(x =>
{
x.For<ISomeInterface>().Add<DefaultImplementation>();
x.For<ISomeInterface>().Add<SomeImplementation>().Named("SomeName");
}
When you call ObjectFactory.GetInstance<ISomeInterface>(); the default instance (the one initialized with Use instead of Add) is the one that will be returned.
So in your case, the set up would look something like:
ObjectFactory.Initialize(x =>
{
// names are arbitrary
x.For<ICommand>().Add<AddAddress>().Named("AddAddress");
x.For<ICommand>().Add<RemoveContact>().Named("RemoveContact");
}
These would be called as pointed out by Mark:
ObjectFactory.GetNamedInstance<ICommand>("AddAddress");
ObjectFactory.GetNamedInstance<ICommand>("RemoveContact");
Hope this helps.
Most IOC containers allow you to register "named instances" of interfaces, allowing you to register several implementations of ICommand, each with its own unique name. In StructureMap, you request them like this:
ObjectFactory.GetNamedInstance<ICommand>("AddAddress");
Have a look at this question to see how you setup the container in StructureMap.

Resources