I have a piece of code with a couple of Modules from different libraries:
install(new AModule())
install(new BModule())
I am getting an error:-
A binding to com.path.to.Class was already configured at com.AModule.provideClass.
at com.BModule...
I need both the modules but they cannot be used together because both have bindings to a particular class. I do not own the 2 libraries so cannot make changes there. How can I solve this issue?
Use Modules.override
If you require the binding present in AModule, use:
install(Modules.override(new BModule()).with(new AModule()));
On the other hand, if you require the binding present in BModule, use:
install(Modules.override(new AModule()).with(new BModule()));
Related
So, we have been trying to xploring bazel as a build system for our organization, since we have a huge monorepo.
One of the problems I'm facing is, we have some code-gen classes which use Jackson's annotation processors to generate immutable copies of some file types.
Eg :
#JsonSerialze
#JsonInclude(JsonInclude.Include.NON_EMPTY)
#Value.Immutable
#JsonDeserialize(as=ImmutableABC.class)
Public abstract class ABC {
...
}
So, for this , I include a java_plugin tag in bazel build file for this module as follows :
Java_plugin(
name="abcgen",
srcs=["src/.../ABC.java"],
Deps=[ {jackson-deps go here}],
processor_class = "org.immutables.processor.ProxyProcessor",
)
This always fails , saying cannot find the ImmutableABC.class file which is referenced in the annotation.
Any ideas? Am I missing the processor class for the Jackson annotations, and also is it possible to include multiple processor classes?
For anyone facing issues as such, ensure generates_api = 1 for your plugin, if the generated classes are used in the library, as for the jackson part, that wasn't really the problem
I'm learning Java and I find that there are many functionalities that are standardized :
logging (using SLF4J)
Persistence (using JPA)
REST (using JAX-RS)
SOAP (using JAX-WS)
etc.
Let's take the Sl4j example : to use it correctly with log4j, we have to import the sl4j api, the sl4j/log4j bridge and the log4j implementation.
Question : In my class, I only communicate with the Slf4j API.
How my application knows about the log4j implementation ?
Can someone explains what's happening exactly under the hood ?
Regards
The OP asks a general question about how implementation is injected in some different cases.
Logging
As sated in many answers, the SLF4J gives the interface and log4j-slf4j gives the implementation.
When you use the following statement:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
private static final Logger LOG = LoggerFactory.getLogger(FooBarClass.class);
...
LOG.debug("Foobar");
This is what is Happening:
We try to get the Logger from the getLogger method declared in the LoggerFactory class :
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
}
...
}
So the magic happens at that statement:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
Because the classpath knows you implemented why, the StaticLoggerBinder implementation is provided by log4j.
As we can notice, log4j provides a with its own implementation:
private final ILoggerFactory loggerFactory;
...
private StaticLoggerBinder() {
loggerFactory = new Log4jLoggerFactory();
}
And that's it !
Persistence
For JPA/Hibernate part, you have to include hibernate-jpa-api and hibernate-* (core, entitymanager, etc).
Let's say you want to create an EntityManagerFactory:
import javax.persitence.EntityManagerFactory
import javax.persitence.Persistence;
...
private static EntityManagerFactory EMF = Peristence.createEntityManagerFactory("foobar", null);
As for List and ArrayList, your classpath is fed with the interface and the implementation thanks to the JARs you import.
The EntityManagerFactory comes from the hibernate-jpa-api where we have a Persistence class.
We can notice that the createEntityManagerFactory method first lists all the providers and for each one of them, an createEntityManagerFactory is fired.
This is where the hibernate comes. It provides an HibernatePersistenceProvider that implements the PersistenceProvider class.
This is how Hibernate is injected.
Slf4j can be used with log4j or any other underlying logging library.
In case of log4j, it uses log4j-slf4j-impl.jar which contains necessary classes for communicating with log4j library.
As per the documentation -
SLF4J doesn't resolve the logging implementation at execution, but
directly at the compilation with a bridging API. So more than the JAR
of SLF4J you need the following JARs : the bridging JAR and the JAR of
the implementation. Here is what you get with Log4J :
If you are talking about dealing with slf4j loggers, like:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FooClass.class);
then it is pretty simple: org.slf4j.Logger is just an interface, which has several implementations. In case of usage library slf4j-log4j12, this interface is implemented by class org.slf4j.impl.Log4jLoggerAdapter which internally contains
final transient org.apache.log4j.Logger logger;
So it is simple adapter which wraps your logging requests and invoke them on log4j logger object:
public void debug(String msg) {
logger.log(FQCN, Level.DEBUG, msg, null);
}
More specifically, proper Logger implementation is produced by LoggerFactory which firstly creates Log4jLoggerFactory via
StaticLoggerBinder.getSingleton().getLoggerFactory()
, latter creates needed Log4jLoggerAdapter instance.
Generally it works via adaptation level like pictured on img from documentation:
The SLF4J manual refers to how under the hoop SLF4J finds the implementation to use : Binding with a logging framework at deployment time.
SLF4J refers the thing that allows to use an implementation (Logback, Log4J, etc...) as "SLF4J bindings" :
As mentioned previously, SLF4J supports various logging frameworks.
The SLF4J distribution ships with several jar files referred to as
"SLF4J bindings", with each binding corresponding to a supported
framework.
You have as many SLF4J bindings as implementations of SLF4J.
And of course, an implementation API may have distinct "SLF4J bindings" according to its version :
To switch logging frameworks, just replace slf4j bindings on your
class path. For example, to switch from java.util.logging to log4j,
just replace slf4j-jdk14-1.7.22.jar with slf4j-log4j12-1.7.22.jar.
The binding with the implementation is not performed at runtime but at compile-time : each SLF4J binding is hardwired at compile time to use one and only one specific logging framework.
So, you have just to include the SLF4J binding in the classpath (for example slf4j-jdk14-1.7.22.jar) so that SLF4J uses it :
SLF4J does not rely on any special class loader machinery. In fact,
each SLF4J binding is hardwired at compile time to use one and only
one specific logging framework. For example, the
slf4j-log4j12-1.7.22.jar binding is bound at compile time to use
log4j. In your code, in addition to slf4j-api-1.7.22.jar, you simply
drop one and only one binding of your choice onto the appropriate
class path location. Do not place more than one binding on your class
path. Here is a graphical illustration of the general idea.
That's why it is generally advised to never place more than one SLF4J binding on the classpath as SLF4J is not designed to choose the implementation at runtime.
I have been looking over the net for an explanation about the injector heirarchy and how/when to use createChildInjector(), but I cannot find a clear and concise explanation.
Here is my use case:
I have a base application module which I use to inject certain context items. This module should be included in every injector instance.
I have a search module which searches a database
I have a search module which searches ElasticSearch. Some of the bindings in this class should override the bindings that are provided in the database search module.
For example, say the database search module contains:
bind(PlaceSearch.class).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(HibernatePersonSearch.class);
And the ElasticSearch module contains:
bind(PersonSearch.class).to(PersonElasticSearch.class);
Is there a way to create an injector that includes the PlaceSearch binding from the database search module and the PersonSearch binding from the ElasticSearch module without creating a separate module that contains
bind(PlaceSearch.class).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(PersonElasticSearch.class);
? Is this a case for Modules.override()? A case for createChildInjector? Thanks ahead of time!
The Modules.override() is not working in Stage.PRODUCTION. You should use PrivateModule where the binding is valid/visible only inside private module, so you can bind different implementation classes to the same interface. Then you can install the Private module to the parent Module, but you have to explicitly expose() all binding you want to make visible for other modules.
Guice - Private Modules
Lets say:
DatabaseSearchModule.java (extends PrivateModule)
bind(PlaceSearch.class).annotatedWith(Names.named("dbSearch")).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(HibernatePersonSearch.class);
expose(PlaceSearch.class).annotatedWith(Names.named("dbSearch"));
EleasticSearchModule.java (extends PrivateModule)
bind(PersonSearch.class).annotatedWith(Names.named("elastic")).to(PersonElasticSearch.class);
expose(PersonSearch.class).annotatedWith(Names.named("elastic"));
Well then you can install it in some Parent abstract or servlet module
MainModule.java
install(new DatabaseSearchModule());
install(new EleasticSearchModule());
bind(OtherClass.class);
OtherClass.java
#Inject #Named("elastic")
private PlaceSearch elasticSearch;
#Inject #Named("dbSearch")
private PlaceSearch dbSearch;
You can use Named annotation or you can create very elegant own binding Annotation.
This is a perfect case for Modules.override().
Most applications shouldn't use child injectors. They add a lot of configuration complexity and have some surprising behavior for corner cases.
I have successfully created an Acceleo module for M2T purposes and am trying to execute it from a Java program.
This is what I tried :
String[] str = {"/home/hamza/workspace/HLRedundancy/model/System1.xmi", "/home/hamza/workspace/HLRedundancy/"};
Generate.main(str);
Generate being the name of the Acceleo module I created and thus, the name of the Java class containing the Acceleo generation methods.
Here is the error I'm always getting :
Exception in thread "main" org.eclipse.acceleo.engine.AcceleoEvaluationException: The type of the first parameter of the main template named 'generateElement' is a proxy.
at org.eclipse.acceleo.engine.service.AcceleoService.doGenerate(AcceleoService.java:566)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.generate(AbstractAcceleoGenerator.java:193)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.doGenerate(AbstractAcceleoGenerator.java:158)
at HighLevelGenerator.main.Generate.doGenerate(Generate.java:250)
at HighLevelGenerator.main.Generate.main(Generate.java:160)
at Execute.main(Execute.java:11)
I've been searching for a while about this error but I have no idea about its cause.
Any idea about a solution to my problem ?
Thanks
The most common cause of this issue is failure in properly registering the metamodel and factory corresponding to your inpu model (System1.xmi).
If you look at the comments in the generated class "Generate.java", you will notice a number of places where we indicate steps to follow if running in standalone. The most important begin registerPackages where you are required to register your metamodel.
If you debug the launch down to the point where the model is loaded (place a breakpoint right after the line model = ModelUtils.load(newModelURI, modelResourceSet);), you can look at the model.eResource().getErrors() list to see whether there were errors loading your model.
You might also be interested in looking at this video describing the process (registration required) .
Check out the first line of your acceleo module,
what is the URI of the metamodel? Does it start with 'http://' ?
Maybe this can help:
Acceleo stand alone - first parameter is proxy
This issue happen when your meta model contains sub-packages and the top package not contain any class.
to solve the problem, add a Dummy class the the top package and regenerate the meta-model code. It worked fine for me.
I have following scenario, I have two packages say com.ws.a and com.ws.b.
Both the packages having web-services classes. com.ws.a contain class TestServoceA which is having method which returns class TestA.
I want to pass this generated class to TestServiceB which is in com.ws.b.
But wsimport tool generate two different classes for both packages like:
com.ws.a.TestA and
com.ws.b.TestA
I want to generate only one class com.ws.a.TestA as a proxy and use it in both namespaces.
How can I do this? If custom binding can help me please give me example.
Thanks.
wsimport will use JAXB for data binding, follow this documentation to specify custom bindings:
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBUsing4.html