Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Oct 21 15:23
    xvik closed #178
  • Oct 21 15:23
    xvik commented #178
  • Oct 21 15:08

    xvik on gh-pages

    Publish 5.4.0 documentation (compare)

  • Oct 21 15:08

    xvik on master

    fix doc typos (compare)

  • Oct 21 15:06

    xvik on gh-pages

    Publish 5.4.0 documentation (compare)

  • Oct 21 15:06

    xvik on master

    fix doc typos (compare)

  • Oct 21 15:01

    xvik on gh-pages

    Publish 5.4.0 documentation (compare)

  • Oct 21 10:42

    xvik on master

    [Gradle Release Plugin] - new v… (compare)

  • Oct 21 10:41

    xvik on 5.4.0

    (compare)

  • Oct 21 10:41

    xvik on master

    [Gradle Release Plugin] - pre t… (compare)

  • Oct 21 10:33

    xvik on master

    update docs (compare)

  • Oct 21 09:10

    xvik on master

    update docs for new version (compare)

  • Oct 20 20:40

    xvik on master

    update docs for new version (compare)

  • Oct 16 10:04

    xvik on master

    unify shared state access metho… (compare)

  • Oct 15 11:44

    xvik on master

    fix typos (compare)

  • Oct 15 11:31

    xvik on master

    add shortcuts to SharedConfigur… (compare)

  • Oct 13 08:30

    dependabot[bot] on gradle

    (compare)

  • Oct 13 08:29

    xvik on master

    Bump spotbugs-annotations from … Merge pull request #185 from xv… (compare)

  • Oct 13 08:29
    xvik closed #185
  • Oct 12 23:39
    codecov-commenter commented #185
Vyacheslav Rusakov
@xvik
Auto config (.enableAutoConfig(getClass().getPackage().getName())) only allows you to avoid manual extension registration: it would search them in classpath automatically. But essentially, it would be the same as manual registration.
6 replies
If you already have too many registrations with environment.jersey().register() then you can only try to enable hk2 bridge so hk could see your guice beans http://xvik.github.io/dropwizard-guicey/4.2.3/guide/configuration/#hk2-bridge
Vyacheslav Rusakov
@xvik
Can't guarantee that everything would work (depends on beans implementation), but it's the only chance. But, if possible, it would be much better to replace all such manual registrations into guicey extensions registration (or just enable auto config)
Note that auto configuration would not be a "black box" for you: you can always enable diagnostic logs (.printDiagnosticInfo()) and see all recognized items.
Yutian Wu
@cielowu
cool, thanks for the explanation, I'll give it a shot.
Yutian Wu
@cielowu

When you use environment.jersey().register() you are just registering object within dropwizard, but not in guice. So if this object requiring other guice beans, it would complain.

So what we did previously is we wait for the injector is created and then do a post initialization using environment.jersey().register() after the guice injector is created. It seems like after using .printLifecyclePhasesDetailed(), the injector has already been created, because it shows me

Guice started, app running

In this case, if the object requires some guice beans, will it still complain?
Using HK2 to manage jersey extension seems works, just want to understand more.

Yes, I'm thinking about moving to use extensions, but that would be MVP1.
One more followup question, if in my application, we've already have a bunch of environment.jersey().register() and environment.lifecycle().manage(). Is is okay for me, first only move the register pieces and keep the other one as it is?
Vyacheslav Rusakov
@xvik

So what we did previously is we wait for the injector is created and then do a post initialization using environment.jersey().register() after the guice injector is created.

Yes, you can do the same with guicey: injector is created before application.run method so you can reference injector there (to obtain guice-managed instance and register it manually in jersey). http://xvik.github.io/dropwizard-guicey/4.2.3/guide/injector/#access-injector

Vyacheslav Rusakov
@xvik

One more followup question, if in my application, we've already have a bunch of environment.jersey().register() and environment.lifecycle().manage(). Is is okay for me, first only move the register pieces and keep the other one as it is?

The main guicey idea was to hide this manual registrations, becuase with guice you always have to reference injector - obtain instance - and register it somewhere. Guicey approach: give me all your extension classes (with classpath scan it would be "i'll find everything myself") and I'll figure out how to register them in dropwizard.

So, with classpath scan enabled, all you need to do is to implement extension (e.g. create MyValueFactoryProfiver class) - everything else (registration) would be automatic.
Vyacheslav Rusakov
@xvik
Of course it would be ok to call environment.jersey().register() or
environment.lifecycle().manage()manually (in some cases it's event required). You gust need to understand what you do.

For example, time-to-time I receive questions like: I do environment.jersey().register(new MySomething()) and inside MySomething I use @Inject to inject other beans; why it doesn't work?

If you clearly understand what is injector and what instances are "guice managed" you can do whatever you want.

Yutian Wu
@cielowu

If you clearly understand what is injector and what instances are "guice managed" you can do whatever you want.

I see. This is very helpful! Thanks!

meryeme0506
@meryeme0506

Hello @xvik, actually I'm working on a project which selects data from multiple databases and inserts it on another one, so I have different DAO classes. I created my own @inTransaction annotation for each DB :
bootstrap.addBundle(GuiceBundle.builder() .enableAutoConfig(monitoringoverviewApplication.class.getPackage().getName()) .bundles(JdbiBundle.<MoConfiguration>forDatabase((conf, env) -> conf.getMO()).withTxAnnotations(MOTransaction.class)) .bundles(JdbiBundle.<MOConfiguration>forDatabase((conf, env) -> conf.getMS()).withTxAnnotations(MStatTransaction.class)) .build());

Then in each DAO classe, I declared the @JdbiRepository and the @InTransaction specific :
Select DAO class :
@JdbiRepository @MStTransaction @RegisterBeanMapper(User.class) public interface FirstDAO { @SqlQuery("SELECT * FROM users") List<User> selectUser(); }

Insert DAO class :
@JdbiRepository @MOTransaction public interface SecondDAO { @SqlBatch("INSERT INTO something values(...)") void insertUser(@BindBean("user") List<User> user); }

In my services class, I'm calling the two functions :

`@Inject FirstDAO firstDAO;
@Inject SecondDAO secondDAO;

public List<User> getData() {
return firstDAO.select();
}

public void insertData(){
secondDAO.insert(this.getDATA());
}

In my resources classs, I'a using my services :
`public class UserResource {

@Inject UserService userService;

public List<User> selectData(){
    return this.userService.getData();
}
public void insert() throws SQLException {  this.userService.insertData(); }

}`

I don't understand why I'm getting this error :
Error in custom provider, java.lang.IllegalStateException: Unit of work not started yet ! while locating ru.vyarus.guicey.jdbi3.unit.UnitManager ! while locating org.jdbi.v3.core.Handle

Vyacheslav Rusakov
@xvik
Hello @meryeme0506 ! Unfortunately, it can't work like this: integration supports only one database.
If you look guice JdbiModule registered by bundle, you can see that it can't bind different instances (no qualifiers used)
I'm not sure why it allow you to start application at all (need to verify this, should fail on binding conflict), but most likley it accepts the latest registered module which is not aware of other transaction annotations (registered in previous modules), so it can't recognize transaction scope.
Vyacheslav Rusakov
@xvik
You'll have to build your own integration module, probably using my integration as example.
Also, you could create a github issue for this feature. I plan to prepare new minor version soon, maybe I'll look this feature too. but can't promise (not sure if it could be done without breaking compatibility).
Shachar Levy
@levyshachar2

@xvik Hi!
we are having some issues with Guicey (dropwizard) and junit with running tests in parallel.
we have many test classes that are all running in parallel (around 14 test classes)
We use dropwizard logging util to write logs to Logz.io

we noticed that we have a random issue when tests are sharing an executer service between multiple threads causing the executer throw a RejectedExecutionException

Our theory of what is happening is as follows

One thread is starting a CT class and initialise a context with a executer service which he submit tasks to
while another thread is in his closing phase so he called the same executer shutdown method.

I wonder if you (or anyone else) encountered this issue.

some references:
getLoggerContext in LoggingUtil (they also reference a workaround Dropwizard did for a concurrency issue)

public DefaultLoggingFactory() { this(LoggingUtil.getLoggerContext(), System.err); } in DefaultLoggingFactory

and finally

LogzioSender.builder() .setDrainTimeoutSec(drainTimeoutSec) .setDebug(debug) .setReporter(LogzioStatusReporter(appender)) .setTasksExecutor(context.scheduledExecutorService) .setHttpsRequestConfiguration(httpsRequestConfiguration) .withDiskQueue() .setFsPercentThreshold(fileSystemFullPercentThreshold) .setQueueDir(bufferDirFile) .setGcPersistedQueueFilesIntervalSeconds(gcPersistedQueueFilesIntervalSeconds) .endDiskQueue() .build()

thank you for any help

my suspicious is that the .setTasksExecutor(context.scheduledExecutorService) retrieve the same scheduledExecutorService for multiple threads causing the issues
Vyacheslav Rusakov
@xvik

@levyshachar2 hi! I agrre that the problem caused by shared executor:
DropwizardTestSupport resets logging context after test

        if (configuration != null) {
            configuration.getLoggingFactory().reset();
        }

which stops LoggerContext and attached executor service
ch.qos.logback.core.ContextBase#stopExecutorService:

if (scheduledExecutorService != null) {
            ExecutorServiceUtil.shutdown(scheduledExecutorService);
            scheduledExecutorService = null;
        }

So one test could init LogzioSender just before executor shutdown and try to use it after.

The actual problem is here:

public DefaultLoggingFactory() {
        this(LoggingUtil.getLoggerContext(), System.err);
    }

which falls into final ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();
One soulutino could be to use a custom logger factory, instantiating different logger contexts, but not sure if its possible (probably would ruin loggers).

Vyacheslav Rusakov
@xvik
The simplier option would be to apply custom executor in testst.
Shachar Levy
@levyshachar2
we will try it @xvik thank you for the help!
Shachar Levy
@levyshachar2

Hi @xvik , wanted to ask you if it's possible to override a configuration - but AFTER guicey is already up.
basically, I need to be able to use injections to do some initialization for the test, but I will need after that to override the value in the config file

Today I have this code

    var app = TestGuiceyAppExtension.forApp(ClaimsServer::class.java)
      .config(configFileName)
      .configOverrides(
        "${ sqsProducerQueueNamesKey }: dev-claim-diary-notification-$uniqueGuid.fifo",
        "${ sqsConsumerQueueNamesKey }: dev-claim-diary-notification-$uniqueGuid.fifo",
      )
      .hooks(GuiceyConfigurationHook {
        it.modulesOverride(ServiceModuleForMondayIntegration(false))
      })
      .create()

and I have this init code in junit5

  @BeforeEach
  fun setup() {
    val id = somethingInjected.doSomething()
}

now I have in my config file
boardId: SomeInt
which I need to replace with the id from the BeforeEach...

is it possible?

something like

  @BeforeEach
  fun setup() {
    val id = somethingInjected.doSomething()
   app.configOverride(...)
}
Vyacheslav Rusakov
@xvik
Hi @levyshachar2 ! No you can't. Simply because dropwizard already parsed and initialized everything with provided configuration. There must be some other solution. For example, I suppose you need to specify exact jms queue name after startup, then you can make lazy factories for producer and consumer isntances and use them everywhere as Provider<MyProducer> (assuming you'll set ID before actual usage). These providers could even support dynamic re-creation of client, so if you set different id it would re-create client (and your code would always obtain actual instance from provider).
Shachar Levy
@levyshachar2

it's not really connected to the queues themselves.
basically, we have an integration with Monday, where we create some groups and tasks there from the system.
Currently how it works is that we have the boardId configured in the configuration file, which is used when we invoke the API with Monday.
The problem starts when after some time the board is too large and we are starting to get flaky tests with Monday (due to their limitations).

what we wanted to do, is to create a new board in each test invocation (or even test class), but in order to tell the service to go to the new board, I need to override the boardId value in the configuration file.

Now I don't know the new boardId when I start guicey , as it's only get created AFTER guicey is already up and running ( as I need the injections to create the board itself)

so it's kinda a chicken and the egg issue.

Vyacheslav Rusakov
@xvik
yep, exactly) I think it would be more correct to call Monday before application startup.
Probably, the most simple way would be to write a small junit extension for this task so you can put it before guicey extension and use already prepared id in configOverride
(as i remmeber junit preserves the order of extensions so should be no problem)
If the Monday api is integrated very tightly into application, you can add dropwizard command, which will use the same guice context for obtaining new id (and you'll just execute this command in the extension)
Vyacheslav Rusakov
@xvik
Or, maybe, you can include random board number generation directly in some service init logic: I suppose there is some service oeprating as Monday high-level client, it might look if configured boardId is -1 then generate random one and use it.
not very pretty (putting test code in prod), but could be faster to implement
Lior Harel
@liorhar

hi @xvik
trying to use TestGuiceyApp in a kotlin project. I'm getting NPE at
at ru.vyarus.dropwizard.guice.test.jupiter.ext.GuiceyExtensionsSupport.postProcessTestInstance
Are there any pitfalls specific to kotlin for the test extension?

Test code is very simple:

@TestGuiceyApp(App::class)
class InsightIntegrationTest {
    @Inject
    lateinit var registries: InsightRegistries

    @Test
    fun testNotNull() {
        assertNotNull(registries)
    }
Vyacheslav Rusakov
@xvik
hi @liorhar! I don't use kotlin at all so can't say why this isn't working. Looks like initialization sequence problem, but have no idea why - it should be pure junit staff and should work. If you can provide me a sample project, I could look it and tell you more (but tomorrow)
Lior Harel
@liorhar

Thanks @xvik
Converted the test to java getting similar NPE

 @TestGuiceyApp(App.class)
public class InsightIntegrationTest2 {
    @Inject
    InsightRegistries insightRegistries;

    @Test
    public void testNotNull() {
        Assertions.assertNotNull(insightRegistries);
    }
}

I'll try to compile a sample project

btw, a test with @ExtendWith(DropwizardExtensionsSupport::class) pass so the guice initialization works.
Vyacheslav Rusakov
@xvik
If java version also not working - it's serious. I'll try to reproduce too
Lior Harel
@liorhar

I tried to reproduce it with guicy sample projects but it worked, couldn't reproduce

I digged a little bit into the code, it seems that the beforeAll method of the extension isn't called in my case, therefore it later fails on the NPE.
Same result even if registering the extension manually using

    @RegisterExtension
    static TestGuiceyAppExtension app = TestGuiceyAppExtension.forApp(App.class).create();
Can you think of any reason why wouldn't the extension initializes properly?
Other tests annotated with DropwizardExtensionsSupport do work
Vyacheslav Rusakov
@xvik
Please tell me what junit version was used when problem appears? And what dropwizard version.
I also thought that beforeAll wasn't called, but, for now, have no idea how this could happen. I'll try to look.
Lior Harel
@liorhar
junit version 5.7.2
DW version 2.0.25
guicy 5.3.0
Lior Harel
@liorhar

I managed to reproduce the problem with guicey sample project

@TestGuiceyApp(SampleApplication.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SampleApplicationTest2 {
    @Inject
    SampleBootstrap bootstrap;

    @Test
    public void testInject() {
        Assertions.assertNotNull(bootstrap);
    }
}

The problem lies in the setting
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
The test passes when removing it.
Guicey expects support in postProcessTestInstance but in the case of per class lifecycle that method is invoked before the beforeAllCallback

Vyacheslav Rusakov
@xvik
Wow! Thank you very much for the investigation!
Lior Harel
@liorhar
Sure, thank you for the helpful library
Vyacheslav Rusakov
@xvik
Fixed: injections would be performed now in beforeEach callback instead of test instance post processor. Thank you!
Lior Harel
@liorhar
That's great news. Thanks again