[英]Java - How to pass unknown implementation of interface to generic method
I have such issue (of course its just an example).我有这样的问题(当然这只是一个例子)。 I have processor where I have to repair a car.
我有处理器,我必须在那里修理汽车。 I have a string as a json of car object.
我有一个字符串作为汽车对象的 json。 I dont know implementation of ServiceStation and I have only class of car implementation.
我不知道 ServiceStation 的实现,我只有汽车实现类。 I have to parse json to car object and provide it to service station.
我必须将 json 解析为汽车对象并将其提供给服务站。 There is any proper solution to achieve this ?
有什么合适的解决方案来实现这一目标吗?
public interface Car {}
public class BMW implements Car {}
public interface ServiceStation<T extends Car> {
public void repair(T car)
}
public class BMWServiceStation<BMW> {
public void repair(BMW car) { ... }
}
public class ServiceStationProcessor {
public void process(String carJson, Settings settings) {
Class<? extends Car> carClass = settings.getCarClass();
ServiceStation serviceStation = settings.getServiceStation();
JavaType javaType = objectMapper.getTypeFactory().constructType(carClass);
Object<? extends Car> obj = objectMapper.readValue(carJson, javaType); <-- ?? something like this?
serviceStation.repair(obj)
}
}
You could have a 'type' field in your json that identifies a concrete Car sub-type (eg 'bmw' or 'mazda').您可以在 json 中有一个“type”字段,用于标识具体的 Car 子类型(例如“bmw”或“mazda”)。 Then you could use annotations on the Car interface to tell Jackson what to instantiate based on the 'type' value.
然后,您可以在 Car 界面上使用注释来告诉 Jackson 根据“类型”值实例化什么。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = BMW.class, name = "bmw"),
@JsonSubTypes.Type(value = Mazda.class, name = "mazda")
})
@JsonIgnoreProperties(ignoreUnknown = true)
public interface Car {
}
Then it's type-safe and logic in processor simplifies:然后它是类型安全的,并且处理器中的逻辑简化了:
public class ServiceStationProcessor {
public void process(String carJson, Settings settings) {
ServiceStation serviceStation = settings.getServiceStation();
Car obj = objectMapper.readValue(carJson, Car.class);
serviceStation.repair(obj);
}
}
You can reach your result with a combination of:您可以通过以下组合来达到您的结果:
This is the "visitor" part of the implementation.这是实现的“访问者”部分。
You should have one single implementation exposing N
methods for the N
different concrete types (instead of having N
different implementations of the same single-method interface).你应该有一个单一的实现,为
N
不同的具体类型公开N
方法(而不是有N
不同的同一个单一方法接口的实现)。
Something like this:像这样的东西:
public interface ServiceStation {
void repair(Bmw bmw);
void repair(Mercedes mercedes);
}
//Single implementation with a dedicated method per type of car
public class ServiceStationImpl implements ServiceStation {
@Override
public void repair(Bmw bmw) {
System.out.println("Repair bmw");
}
@Override
public void repair(Mercedes mercedes) {
System.out.println("Repair mercedes");
}
}
This will be the "visited" part of your implementation.这将是您实现的“访问”部分。
You defined Car
as being an interface
.您将
Car
定义为interface
。
Jackson allows deserialization of sub types but using abstract class
rather than interface
. Jackson 允许反序列化子类型,但使用
abstract class
而不是interface
。
Also, I take chance to add an abstract method which accepts a ServiceStation
.此外,我有机会添加一个接受
ServiceStation
的抽象方法。 That will allow each concrete car implementation to let the ServiceStation (the visitor) "visit" themselves (the visited):这将允许每个具体的汽车实现让 ServiceStation(访问者)“访问”自己(被访问者):
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(
{
@JsonSubTypes.Type(value = Bmw.class, name = "Bmw"),
@JsonSubTypes.Type(value = Mercedes.class, name = "Mercedes")
}
)
public abstract class Car {
public abstract void accept(ServiceStation serviceStation);
}
public final class Bmw extends Car {
@JsonIgnore
private final String type = "Bmw";
@Override
public void accept(ServiceStation serviceStation) {
serviceStation.repair(this); //<-- will call the Bmw method of the service station
}
}
public final class Mercedes extends Car {
@JsonIgnore
private final String type = "Mercedes";
@Override
public void accept(ServiceStation serviceStation) {
serviceStation.repair(this); //<-- will call the Mercedes method of the service station
}
}
At this point, it becomes as simple as this:此时,它变得如此简单:
public class ServiceStationProcessor {
public void process(String carJson, Settings settings) throws JsonProcessingException {
Class<? extends Car> clazz = settings.getCarClass(); //<-- get the car class as you already do
ServiceStation serviceStation = settings.getServiceStation(); //<-- get the service station
objectMapper.readValue(carJson, clazz).accept(serviceStation); //<-- deserialize the json into the concrete car class (Jackson will pick the right type of car), then ask the car to accept the service station (the car will dispatch to the correct type)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.