I'm building a plugin for Jira. I want to add a caching-layer so I wanted to use the com.atlassian.cache.CacheManager. I have to inject this via an argument / setter.
Since I'm extending an other class I wanted to inject this via a setter, but for some reason it returns null all the time.
import com.atlassian.cache.Cache;
import com.atlassian.cache.CacheLoader;
import com.atlassian.cache.CacheManager;
import com.atlassian.cache.CacheSettingsBuilder;
public class Foo extends AbstractJiraContextProvider
{
private CacheManager cacheManager;
public void setCacheManager(CacheManager cacheManager) {
//It does not get past this function..
this.cacheManager = cacheManager;
}
#Override
public Map getContextMap(ApplicationUser user, JiraHelper jiraHelper) {
cache = this.cacheManager.getCache("bar");
}
}
I also tried this by doing the following:
public Foo(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
After that the plugin does nothing anymore. I do not get errors, but it just gives 0 output.
I used this for documentation: https://developer.atlassian.com/confdev/confluence-plugin-guide/writing-confluence-plugins/accessing-confluence-components-from-plugin-modules
And https://developer.atlassian.com/confdev/development-resources/confluence-developer-faq/how-do-i-cache-data-in-a-plugin#HowdoIcachedatainaplugin?-Instructions
Your question mentions JIRA, but the documentation links that you provide are for Confluence (and outdated).
If you're developing an add-on for a recent version of JIRA (7.2+) then injecting components is now handled by Atlassian Spring Scanner 2, so everything works with annotations.
If you follow the instructions listed here then you should be able to inject components via a constructor like so:
#Component
public class MyService {
private final IssueService issueService;
private final InternalComponent internalComponent;
#Inject
public MyService(#ComponentImport final IssueService issueService,final InternalComponent internalComponent) {
this.issueService = issueService;
this.internalComponent = internalComponent;
}
}
Related
In out project we don't use setter or filed injection, we use only constructor injection, and I know that both options 1. and 2. may work.
Is it unsafe to work with beans in constructor in that case?
Or spring boot 2+ makes something, and I should better use option 1. instead of 2. I can't imagine case when option 1 will go wrong
#Component
#ConfigurationProperties("config")
public class ServiceConfigProperties {
// .... some code
}
Can be unsafe? - but it looks better
#Component
public class Service {
private boolean skipCheck;
public Service(ServiceConfigProperties configProps) {
this.skipCheck = configProps.isSkipCheck();
}
}
Can't be unsafe?
#Component
public class Service {
private boolean skipCheck;
private ServiceConfigProperties configProps;
public Service(ServiceConfigProperties configProps) {
this.configProps= configProps;
}
#PostConstruct
public void initConfig() {
this.skipCheck= configProps.isSkipCheck();
}
}
With a couple of caveats, interacting with constructor-injected beans inside the constructor is completely safe.
I'm trying to achieve something like this:
#Controller
public SomeController {
#CustomConfig("var.a")
private String varA;
#CustomConfig("var.b")
private String varB;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String get() {
return varA;
}
}
CustomConfig would be an #Interface class that accepts one value parameter. The reason why we are not using #Value is because this will not come from config file but from API (such as https://getconfig.com/get?key=var.a). So we are going to make HTTP request to inject it.
So far I've only manage to make something work if the varA and varB is inside get() method as parameter, by using below in a class that extends WebMvcConfigurerAdapter:
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
CustomConfigResolver resolver = new CustomConfigResolver();
argumentResolvers.add(resolver);
}
And inside CustomComfigResolver.resolveArgument() we would do the HTTP query, but that's not really what we wanted, we need it to be injected as class variable.
Does anyone have experience in resolving it at class variable level?
Thank you
This could work if you use #Value instead of your own custom annotation. This uses the built in environment:
#Order(Ordered.HIGHEST_PRECEDENCE)
#Configuration
public class TcpIpPropertySourceConfig implements InitializingBean {
#Autowired
private ConfigurableEnvironment env;
#Autowired
private RestTemplate rest;
public void afterPropertiesSet() {
// Call your api using Resttemplate
RemoteProperties props = //Rest Call here;
// Add your source to the environment.
MutablePropertySources sources = env.getPropertySources();
sources.addFirst(new PropertiesPropertySource("customSourceName", props)
}
}
What you are trying to achieve is difficult when you start to consider "unhappy" scenarios. Server down / not reachable. You need to account for all of that in the method above.
I would highly recommend to instead use Spring Cloud Config. Great guide on that is here: https://www.baeldung.com/spring-cloud-configuration
This provides:
- Reloading of your #Value() properties, so no custom annotation needed.
- A more stable server and great Spring integration out of the box.
Best of all, it is easy to apply Retries and Backoffs if the configuration server goes down (see https://stackoverflow.com/a/44203216/2082699). This will make sure your app doesn't just crash when the server is not available.
I've seen this question asked a lot on here, but none of the answers have helped me in my situation.
I'm using square sdk which prompts me to create the client like this, before using it.
import com.squareup.square.SquareClient;
import com.squareup.square.Environment;
SquareClient square = new SquareClient.Builder()
.environment(Environment.SANDBOX)
.accessToken("YOUR_SANDBOX_ACCESS_TOKEN")
.build();
Given the service looks something like this, spring will not able to find the required bean. And will give an error like,
No qualifying bean of type 'squareClient'
So the question I have is how to load the two paramters into the service using dependecy injection in order to make square service testable.
#Service
public class SquareService {
private final SquareClient squareClient;
public SquareService(SquareClient squareClient) {
this.squareClient = squareClient;
}
}
And my test I have
#Before
public void setup() {
sut = new SquareService(new SquareClient.Builder()
.environment(Environment.SANDBOX)
.accessToken("YOUR_SANDBOX_ACCESS_TOKEN")
.build());
}
You can create a #Configuration class and create the bean manually:
#Configuration
public class SquareConfiguration {
#Value("${my.config.sandboxAccessToken}")
private String sandboxAccessToken;
#Bean
public SquareService createSquareService(){
return new SquareService(new SquareClient.Builder()
.environment(Environment.SANDBOX)
.accessToken(this.sandboxAccessToken)
.build());
}
}
First of all, I'm a relative noob to Spring Boot, so keep that in mind.
I've got a REST api in which I'm trying to minimize database calls for the same object and I've determined that using a Spring Bean scoped to the Request is what I want. Assuming that is correct, here is what I'm trying to do:
1) Controller takes in a validated PhotoImportCommandDto command
PhotoCommandController
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> importPhoto(#Valid #RequestBody PhotoImportCommandDto command){
...
}
2) PhotoImportCommandDto is validated. Note the custom #UserExistsConstraint which validates that the user exists in the database by calling a service method.
PhotoImportCommandDto
#Component
public class PhotoImportCommandDto extends BaseCommand {
#NotNull(message = "userId must not be null!")
#UserExistsConstraint
private Long userId;
...
}
What I would like to do is somehow set a Spring Bean of the user that is validated in the #UserExistsConstraint and reference it in various methods that might be called throughout a Http request, but I'm not really sure how to do that. Since I've never really created my own Spring Beans, I don't know how to proceed. I've read various guides like this, but am still lost in how to implement it in my code.
Any help/examples would be much appreciated.
You can use the #Bean annotation.
#Configuration
public class MyConfiguration {
#Bean({"validUser"})
public User validUser() {
User user;
//instantiate user either from DB or anywhere else
return user;
}
then you can obtain the validUser.
#Component
public class PhotoImportCommandDto extends BaseCommand {
#Autowired
#Qualifier("validUser")
private User validUser;
...
}
I don't really know how to make annotations in Java. Anyway, in Spring, checking where the User exists in the DataBase or not is one line of code:
userRepository.findOne(user) == null
That is accomplished by the Spring Data JPA project:
Create a JPA Entity User.
Set the spring.datasource.url and login/password in the
resources/application.properties.
Create this interface:
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
}
Note, Spring implements it behind the scences.
Inject this interface into your RestController (or any other Spring bean):
private UserRepository userRepository ;
**constructor**(UserRepository ur){
userRepository = ur;
}
Note, a Spring Bean is any class annotated #Component (this includes stereotype annotations like Controller, Repository - just look up the contents of an annotation, it may use #Component internally) or returned from a method which is annotated #Bean (can only be on the Component or Configuration class). A Component is injected by searching the classpath, Bean is injected more naturally.
Also note, injecting is specifying #Autowired annotation on field or constructor, on a factory method, or on a setter. The documentation recommends that you inject required dependencies into constructor and non-required into the setter.
Also note, if you're injecting into a constructor and it is clean by the arguments, you may omit #Autowired annotation, Spring will figure it out.
Call its method findOne.
So, you can do one of the following:
Inject the userRepository into the #RestController constructor (as shown above). I would do that.
Inject the userRepository into the #Service (internally #Component) class that will do this sorts of thing for you. Maybe you can play with it to create an annotation.
p.s. Use #PostMapping instead of #RequestMapping(method = RequestMethod.POST)
p.p.s. If ever in doubt, go to the official documentation page and just press CTRL-F: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ Note the current word, that will always take you to the latest version.
p.p.p.s Each Spring project has its own .io webpage as well as quick Get Started Guides where you can quickly see the sample project with explanations expecting you to know nothing.
Hope that helps! :)
Don't forget to mark the answer as accepted if you wish
Using Jose's input, I took a bit of a different route.
Here's what I did:
I created a ValidatedUser class:
#RequestScope
#Component
public class ValidatedUser {
private UserEntity user;
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
}
and I also created a wrapper class HttpRequestScopeConfig to capture all variables to use over the course of an Http Request to the api.
#Component
public class HttpRequestScopeConfig {
#Autowired
private ValidatedUser validatedUser;
...
public UserEntity getValidatedUser() {
return validatedUser.getUser();
}
public void setValidatedUser(UserEntity validatedUser) {
this.validatedUser.setUser(validatedUser);
}
...
}
In my UserExistsConstraintValidator (which is the impl of #UserExistsConstraint, I set the validatedUser in the httpRequestScopeConfig:
public class UserExistsConstraintValidator implements ConstraintValidator<UserExistsConstraint, Long> {
//private Log log = LogFactory.getLog(EmailExistsConstraintValidator.class);
#Autowired
private UserCommandService svc;
#Autowired
private HttpRequestScopeConfig httpRequestScope;
#Override
public void initialize(UserExistsConstraint userId) {
}
#Override
public boolean isValid(Long userIdField, ConstraintValidatorContext context) {
try {
UserEntity user = svc.findUserOfAnyStatus((Long) userIdField);
if (user != null) {
httpRequestScope.setValidatedUser(user);
return true;
}
} catch (Exception e) {
//log.error(e);
}
return false;
}
}
Now, I can access these variables throughout the rest of my service layers by autowiring HttpRequestScopeConfig where necessary.
I'm currently trying to implement injection in a Java console application using Guice. The application imports XML files in a database. Every import operation is done in an AbstractImporter, which can either be a UserImporter, a ScheduleImporter, etc.
public class ScheduleMigrator extends AbstractMigrator {
private final UserImporter userImporter;
private final ScheduleImporterFactory scheduleImporterFactory;
#Inject
public ScheduleMigrator(UserImporter userImporter,
ScheduleImporterFactory scheduleImporterFactory) {
this.userImporter = userImporter;
this.scheduleImporterFactory = scheduleImporterFactory;
}
public void migrate() {
// Migrate users
userImporter.run();
// Migrate schedules for each type
for (ScheduleType scheduleTypes : ScheduleType.values()) {
ScheduleImporter importer =
scheduleImporterFactory.create(scheduleTypes);
importer.run();
}
}
}
public class UserImporter extends AbstractImporter {
private final UserTransformer userTransformer;
private final ConfigurationService configurationService;
#Inject
public UserImporter(UserTransformer userTransformer,
ConfigurationService configurationService) {
this.userTransformer = userTransformer;
this.configurationService = configurationService;
}
public void run() {
// do stuff here
}
}
#Singleton
public class UserTransformer {
// ...code ommited...
}
#ImporterScoped
public class ConfigurationService {
// ...code ommited...
}
I have successfully created my own scope (#ImporterScoped) for classes that should only be available and instantiated only in an Importer. The scope was created by following the steps in the wiki. My problem is, how should I enter and exit the scope in ScheduleMigrator?
As you can see in ScheduleMigrator, each Importer is injected and its run() method is invoked. There are also factories (based on Guice's #AssistedInject feature). This is where I want each scope to start and end, UserImporter and ScheduleImporterFactory should run in their own scope.
This is a rough idea of what I'm trying to achieve:
importerScope.enter();
(new UserImporter()).run();
importerScope.exit();
Guice's documentation mentions the use of interceptors, but I'm a little lost on how it can be implemented.
Using AOP seems a very over-engineered approach and might introduce problems. When do I enter the scope? When do I exit? What happens if I instantiate two Importer objects?
Instead, I added a runScoped method in AbstractMigrator that takes a Runnable and executes it. Using injection I get the ImporterScope scope, enter and exit it appropriately.
protected void runScoped(Runnable function)
{
scenarioScope.enter();
try {
function.run();
}
finally {
scenarioScope.exit();
}
}
Usage:
runScoped(() -> {
ScheduleImporter importer =
scheduleImporterFactory.create(scheduleTypes);
importer.run();
});
This introduces one problem though. In ScheduleMigrator, I can't have Importers injected, because their instantiation would occur outside of a scope and Guice throws an OutOfScopeException. I had to wrap each Importer in a Provider.
private final Provider<UserImporter> userImporterProvider;
runScoped(() -> {
UserImporter importer = userImporterProvider.get();
importer.run();
});