How can i get spring-boot main-class package name - java

I want to make a spring-boot starter,so i need to get package name of application main-class.
How can i get it?
Sometimes,you can use listener for spring boot,but it must configure in application.properties.

import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.context.ApplicationContext;
AutoConfigurationPackages.get(context.getAutowireCapableBeanFactory())

By this method, you can get the package of you current class.
MethodHandles.lookup().lookupClass().getPackage().getName()

You could use the fact that the main class will problably be annotated with #SpringBootApplication and search for that class in the Spring Context. Implementing something like:
#Service
public class ApplicationFinder {
#Autowired private ApplicationContext context;
public String findBootClass() {
Map<String, Object> candidates = context.getBeansWithAnnotation(SpringBootApplication.class);
return candidates.isEmpty() ? null : candidates.values().toArray()[0].getClass();
}
}
Once you jave the class name you can string slice it to extract the package.

Related

#Value not Injecting ANY value

I'm learning how to create a RESTful API with Springboot, and the #Value tag is not injecting values from application.properties, nor is it injecting values specified in the tag itself. I have my project structured as such:
api
config
controllers
model
services
SpringApplication.java
resources
application.properties
Strangely, this behavior only seems to occur within files located in my "services" folder. The #Value tag works as expected in files located in my "controllers" folder. Below are examples of what I am doing:
#Value("${var}")
String variable
"var" is defined in application.properties as var=some_stringbut variable is still initialized as 'null'
#Value("I am directly assigning a value to this variable, but it still comes out null")
String variable
I believe I am using the correct import: import org.springframework.beans.factory.annotation.Value.
At first I just thought the "services" folder was blind to the directory where application.properties is located, but after trying to directly inject values, I'm not so sure what to think.
Edit
All of the classes in the services folder are annotated with #Service and nothing else. Below is what the class looks like. I've opted to leave out implementations of the methods, other variables, and irrelevant imports. The code/methods all work as expected when hard-coding the variables. My focus is the #Value tag.
package myapi.api.services;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
#Service
public class MyService {
#Value("${var}")
String variable;
public List<Data> getData() {
return new ArrayList<Data>();
}
public void postData() {
}
Edit 2
Below is the APIController class, stored in the "controllers" folder. Again, I've opted to leave out irrelevant methods/imports/variables. I would also like to note, that the #Value tag works as expected in this class.
package myapi.api.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import myapi.api.services.MyService;
import lombok.RequiredArgsConstructor;
#RestController
#RequestMapping("api")
#RequiredArgsConstructor
public class APIController {
#Autowired
private final static MyService myService = new MyService();
#GetMapping("/getdata")
public List<Data> getData() {
return myService.getData();
}
}
#Autowired
private final static MyService myService = new MyService();
Three issues:
First, you cannot have a new operator. Spring controls the lifecycle of your class instances. It will call new for you in the background. Remove the entire new operator stanza.
Next: your your field cannot be final. After construction of the class, Spring will need to modify that field with a proxy. Remove the final declaration;
Finally: your field cannot be static. static variables have a certain lifecycle with the JVM, and you need to let the Spring framework manage your lifecycle. remove the static operator.
The correct declaration should be:
#Autowired
private MyService myService;

Adding Apache Camel custom component/endpoint in a Spring application

I'm trying to implement a custom endpoint in a Spring Boot application.
Goal is to use routes as: from("...").process("...").to("my:...");
Now, I have 3 classes: a DefaultConsumer, a DefaultEndpoint, a DefaultComponent:
package com.my.endpoint;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.support.DefaultEndpoint;
public class MyEndpoint extends DefaultEndpoint {
public MyEndpoint(String uri, MyComponent myComponent) {
}
...
}
package com.my.endpoint;
import org.apache.camel.Endpoint;
import org.apache.camel.Processor;
import org.apache.camel.support.DefaultConsumer;
public class MyConsumer extends DefaultConsumer {
public MyConsumer(Endpoint endpoint, Processor processor) {
super(endpoint, processor);
}
}
package com.my.endpoint;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.spi.annotations.Component;
import org.apache.camel.support.DefaultComponent;
import java.util.Map;
#Component("my")
public class MyComponent extends DefaultComponent {
public MyComponent(CamelContext camelContext) {
super(camelContext);
}
...
}
Now: how can I register?
In a Spring configuration class, I have:
#Override
public void configure() throws Exception {
camelContext.addComponent("my", new MyComponent(camelContext));
But is not working:
Caused by: org.apache.camel.NoSuchEndpointException: No endpoint could be found for: my, please check your classpath contains the needed Camel component jar.
So, I added the META-INF file in services/org/apache/camel/component/my:
class=com.my.endpoint.MyComponent
But also this, is not working.
There is no complete tutorial on how to implement this.
Any help?
Note: I'm trying to implement an Endpoint because I need to integrate my systems using my data types. I tried using Transformer but failed because of this: Set a custom DataType in Apache Camel Processor
Before, I tried using data type converter, but failed because of this (marked duplicate because people are too lazy to really understand questions): Enforce type conversion on Rest consumer in Apache Camel
I've FULLY read "Apache Camel In Action, Second Edition" but, at the moment, I can't continue with my project because of?
This is because custom component must be annotated by #UriEndpoint annotation.
Another way to solve this problem: Set EndpointUri via Constructor or by implementing createEndpointUri() in MyEndpoint.
So easiest way might be changing your constructor to:
public MyEndpoint(String uri, MyComponent myComponent) {
super(uri, myComponent);
}

SpringBoot #Autowire why does this example work?

I have created this class:
import org.springframework.stereotype.Component;
...
#Component("notTheNameTestMe") //shouldnt this only work with testMe ?
public class TestMe {
public void showMsg() {
System.out.println("Autowiring works");
}
}
And I'm using it this way in a second class (or better: controller):
import com.example.TestMe; //shouldnt this be not necessary with autowire? But getting error else...
...
#Autowired
private TestMe testMe;
...
this.testMe.showMsg();
But this works perfectly (so maybe Im not really using autowire here?), it even works if I rename the whole TestMe class to TestMeSomething (if I adjust the import in the second class)
I dont really understand what #Autowired does. I thought it just scans for SpringBoot Components (which are named by the string in #Component() and when it finds a match it Injects the dependancy. But in my example the match is impossible and I still can see the message "Autowiring works" in the console. This shouldnt be like this if I would really use autowire here or? What am I understanding in a wrong way? What is the difference to using new TestMe() then? I have the dependancy already with the import or? So not a real dependancy injection, or?
Spring is not operating on the name in the #Component annotation. Rather it's using the name of the class. It's simply finding a class named TestMe because that's the type of the variable you've annotated with #Autowired.

Usage of non public classes in spring java-based config

It seems to be a simple question but yet i couldn't find clear answer while searching documentation and forums. I'm migrating from xml to java-based config (Spring 5.1.9). Due to some legacy restrictions in xml config i need to create a bean from some side library's non public class:
SampleClass.class
package side.library
class SampleClass {
//... some code here
}
context.xml
...
<bean id = "sampleId" class "side.library.SampleClass">
...
And this works fine since Spring uses reflection inside and it creates bean without any problems at compile/runtime, but in java-based config usage of such class leads to an access error:
package my.configuration;
import side.library.SampleClass; // 'side.library.SampleClass' is not public in 'side.library'. Cannot be accessed from outside package
#Configuration
public class JavaConfiguration{
#Bean
public SampleClass sampleClass() {
return new SampleClass(); // same error text
}
}
So, what is the proper way to deal with this sutiation? Using reflection libs in #Configuration class to reach this class seems to be a bad idea.
just a workaround: create a wrapper class in the outer project in the same package and use this class in your configuration.
package com.legacy;
public class Wrapper {
private LegacyImpl legacyImpl;
public Wrapper()
this.legacyImpl = new LegacyImpl();
}
public void wrappedMethod() {
this.legacyImpl.wrappedMethod();
}
}

Play Framework Dependency Injection

I've been looking all over Google to find some useful information on how to use Guice/Spring DI in Play Framework 2.1
What I want to do is to Inject several Services in some DAO's and vice versa.
Just need some clarification on this - With play 2.1, do you have to use an # annotation within the routes file for DI?
I've looked at this guide here - https://github.com/playframework/Play20/blob/master/documentation/manual/javaGuide/main/inject/JavaInjection.md
and applied the following steps creating a Global class in app and adding the GUICE dependencies in Build.scala but keep on getting a null pointer exception when invoking on the injected object.
Has anyone been able to get DI working in Play 2.1 using Guice? I've seen examples across the internet but they all seem to be using DI within the controller.
I noticed you are using Java. Here is how I got it to work for injecting into a controller.
First, I created the following 4 classes :
MyController:
package controllers;
import play.mvc.*;
import javax.inject.Inject;
public class MyController extends Controller {
#Inject
private MyInterface myInterface;
public Result someActionMethodThatUsesMyInterface(){
return ok(myInterface.foo());
}
}
MyInterface:
package models;
public interface MyInterface {
String foo();
}
MyImplementation2Inject:
package models;
public class MyImplementation2Inject implements MyInterface {
public String foo() {
return "Hi mom!";
}
}
MyComponentModule:
package modules;
import com.google.inject.AbstractModule;
import models.MyInterface;
import models.MyImplementation2Inject;
public class ComponentModule extends AbstractModule {
#Override
protected void configure() {
bind(MyInterface.class).
to(MyImplementation2Inject.class);
}
}
Now the final part, that took me a silly long time to figure out, was to register the module. You do this by adding the following line to the end of the application.conf file, which is located in the conf directory:
play.modules.enabled += "modules.MyComponentModule"
I hope this was helpful to you. :)
I use cake pattern and my own version of Global overriding getControllerInstance
https://github.com/benjaminparker/play-inject
Cheers
Ben
Sorry, this is a late response, but here's our example
https://github.com/typesafehub/play-guice
Have you tried using some different approach to DI than Guice?
We also tried implementing a project with Guice or Spring but ended in registering our dependencies in objects that implement trait such as:
trait Registry {
def userDao: UserDao
...
}
object Registry {
var current: Registry = _
}
object Environnment {
object Dev extends Registry {
val userDao = ...
//implement your environment for develpment here
}
object Test extends Registry {
val userDao = ...
//implement your ennviroment for tests here e.g. with mock objects
}
}
Another good approach wich might fit for you is the cake pattern (just google for it).

Categories

Resources