Best code practice for not duplicate your code in spring controller by abstract.
I've got two controllers for example
#Controller
public class DoSomethingController {
private Entity helpfulMethod(Form form) {
Entity e = new Entity();
return e;
}
#PostMapping("/something")
public String something(Form form){
helpfulMethod(form);
}
}
#Controller
public class DoSomethingElseController {
private Entity helpfulMethod(Form form) {
Entity e = new Entity();
return e;
}
#PostMapping("/somethingElse")
public String somethingElse(Form form){
helpfulMethod(form);
}
}
How to take helpfulMethod out and connect them from outside using abstract?
I guess you need to introduce a super class for both the controllers
public abstract class BaseDoSomethingController {
protected Entity helpfulMethod(Form form) {
Entity e = new Entity();
return e;
}
}
and let both your controllers inherit the base class
#Controller
public class DoSomethingController extends BaseDoSomethingController {
#PostMapping("/something")
public String something(Form form){
helpfulMethod(form);
}
}
and the same for the second controller
Related
My scenario is need yo track entity property changes. I have used Hibernate PostUpdateEventListener interface to achieve that.
Following is my generic event listener class.
public abstract class EventListener<DOMAIN extends BaseModel> implements PostUpdateEventListener {
public abstract LogSupport getService();
public abstract BaseModel getLogDomain(DOMAIN domain);
#SuppressWarnings("unchecked")
private DOMAIN getDomain(BaseModel model) {
return (DOMAIN) model;
}
public void postUpdate(PostUpdateEvent event, BaseModel model) {
getService().createUpdateLog(getDomain(model), getPostUpdateEventNotes(event));
}
private String getPostUpdateEventNotes(PostUpdateEvent event) {
StringBuilder sb = new StringBuilder();
for (int p : event.getDirtyProperties()) {
sb.append("\t");
sb.append(event.getPersister().getEntityMetamodel().getProperties()[p].getName());
sb.append(" (Old value: ")
.append(event.getOldState()[p])
.append(", New value: ")
.append(event.getState()[p])
.append(")\n");
}
System.out.println(sb.toString());
return sb.toString();
}
}
And this is my custom entity listener.
#Component
public class AssetEventListener extends EventListener<Asset> {
private static final long serialVersionUID = -6076678526514705909L;
#Autowired
#Qualifier("assetLogService")
private LogSupport logSupport;
#Override
public LogSupport getService() {
AutowireHelper.autowire(this, logSupport);
return logSupport;
}
#PostPersist
public void onPostInsert(PostInsertEvent event) {
if (event.getEntity() instanceof BaseModel){
super.postPersist( event, (BaseModel) event.getEntity() );
}
}
#Override
public void onPostUpdate(PostUpdateEvent event) {
if (event.getEntity() instanceof BaseModel){
super.postUpdate( event, (BaseModel) event.getEntity() );
}
}
#Override
public BaseModel getLogDomain(Asset domain) {
return domain;
}
#Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return false;
}
}
And I called it from #EntityListeners
#Entity
#Table(name = "tbl_asset")
#EntityListeners({ AssetEventListener.class })
public class Asset extends BaseModel {
}
Listener not call when update the entity. Any help would be greatly appreciated.
Thanks,
#Service
abstract class A {
protected MyObj obj;
protected A(MyObj obj) {
this.obj = obj;
}
public abstract XYZ getTrade();
}
#Service
public class B extends A {
B(MyObj obj) {
super(obj);
}
public XYZ getTrade() {}
}
#Service
public class C extends A {
C(MyObj obj) {
super(obj);
}
public XYZ getTrade() {}
}
#Controller
public class MyController {
#GemMapping("/test")
public void test() {
MyObj obj = new MyObj();
if(condition 1) {
//call getTrade() method of class B
}
if(condition 2) {
//call getTrade() method of class C
}
}
}
MyObj is a user-defined POJO that is not managed bean.
I have the above classes. now I have to call getTrade() method based on some condition in Controller. Could you please help/advise?
this answer is based on the information provided by the question.
to inject beans you could do:
#Controller
public class MyController {
private final B b;
private final C c;
public MyController (B b, C c) {
this.b = b;
this.c = c;
}
.........
}
in this case, beans must have to have one no-args constructor. so, In your case what you can do is have a no-args constructor in each service. then set your myObj by setter. that will do the trick.
If you want to achieve polyformism on your sevices you need to add a Qualifier in your classes B and C. So the question now became how to inject a service dynamically on runtime, and this is answered here:
How to dynamically inject a service using a runtime "qualifier" variable?
I can't manage to inject a property from application.yml to a spring data #Query.
The following results in an EL1008E error:
public interface MyRepository extends JpaRepository<MyEntity, Long> {
#Query("select e from MyEntity e where e.foo = :foo and e.env= ?#{env}")
MyEntity findByFoo(#Param("foo") String foo);
}
According to this blog it is possible to inject a property of spring's principal, which is not very different from what I would like to do.
Any hints on this?
I should really stop asking questions and answer them by myself shortly after ... That is not on purpose.
The mentioned blog has the solution included. Add this:
public class PropertyEvaluationContextExtension extends EvaluationContextExtensionSupport {
private final MyProps p;
public PropertyEvaluationContextExtension(final MyProps p) {
this.p= p;
}
#Override
public String getExtensionId() {
return "foo";
}
#Override
public MyProps getRootObject() {
return this.p;
}
}
#Configuration
public class PropertyConfig {
private final MyProps p;
public PropertyConfig(final MyProps p) {
this.p= p;
}
#Bean
EvaluationContextExtensionSupport propertyExtension() {
return new PropertyEvaluationContextExtension(p);
}
}
Now every property of MyProps is accessible via SpEL.
Is it possible to use inheritance in Spring Boot YML configuration classes? If so, how would that be accomplished?
For example:
#ConfigurationProperties(prefix="my-config")
public class Config {
List<Vehicle> vehicles;
}
And the class (or interface) "Vehicle" has two implementations: Truck and Car. So the YAML might look like:
my.config.vehicles:
-
type: car
seats: 3
-
type: truck
axles: 3
I do not think it is possible (at least not that I know of). You could however design your code as follow:
Inject the properties into a Builder object
Define an object with all properties, which we'll call the VehicleBuilder (or factory, you choose its name).
The VehicleBuilders are injected from the Yaml.
You can then retrieve each builder's vehicle in a #PostConstruct block. The code:
#ConfigurationProperties(prefix="my-config")
#Component
public class Config {
private List<VehicleBuilder> vehicles = new ArrayList<VehicleBuilder>();
private List<Vehicle> concreteVehicles;
public List<VehicleBuilder> getVehicles() {
return vehicles;
}
public List<Vehicle> getConcreteVehicles() {
return concreteVehicles;
}
#PostConstruct
protected void postConstruct(){
concreteVehicles = vehicles.stream().map(f -> f.get())
.collect(Collectors.<Vehicle>toList());
}
}
The builder:
public class VehicleBuilder {
private String type;
private int seats;
private int axles;
public Vehicle get() {
if ("car".equals(type)) {
return new Car(seats);
} else if ("truck".equals(type)) {
return new Trunk(axles);
}
throw new AssertionError();
}
public void setType(String type) {
this.type = type;
}
public void setSeats(int seats) {
this.seats = seats;
}
public void setAxles(int axles) {
this.axles = axles;
}
}
i try make a generic controller with some methods, so i don´t need re-writer common codes, but don´t work, why???
#Controller("/home/teste")
public class CtrlTeste extends ControladorGenericoSpring<Assistenciado>
{
public String path;
public CtrlTeste()
{
super(Assistenciado.class);
path = "/home/teste";
setPacoteServico("servico.assistenciado");
setPrefixo("Serv");
setNomeEntidade("Assistênciado");
}
#RequestMapping
public String teste(#RequestParam(value = "id", required= true)Long id, Model model)
{
Assistenciado ass = getServico().buscarPorId(id);
model.addAttribute("assistenciado", ass);
return "/home";
}
}
You're currently specifying the name of the bean. Try with:
#Controller
#RequestMapping("/home/teste")
public class CtrlTeste extends ControladorGenericoSpring<Assistenciado> {
...
}