Java service architecture - java

I want to design an API which reads a large text file, extracts the relevant info and returns a list of Foo objects like this:
interface FooService {
Optional<Foo> getFoo(Bar bar);
}
The format of the text file and the way it is parsed is always the same. The only thing that can vary is the location of the file, i.e. it could be a file on the local system or an URL. So I created an AbstractFooService:
class AbstractFooService implements FooService {
Map<Bar, Foo> registry;
AbstractFooService(InputStream is) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
registry = reader.lines()
.map(l -> l.split(';'))
.map(a -> new Foo(a[0]), a[1]))
.collect(Collectors.groupingBy(...));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
Optional<Foo> getFoo(Bar bar) {
return Optional.ofNullable(registry.get(bar));
}
}
Concrete implementations would just call the super constructor with an InputStream:
class UrlFooService extends AbstractFooService {
UrlFooService(String url) {
super(createStream(url));
}
private static InputStream createStream(final String url) {
try {
return new URL(string).openStream();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
Is that a sound API design or is there a 'better' way to achieve my goal? I.e. is it smart to call the super constructor with an InputStream or would it be better to have a separate load() method that opens the stream when needed?

I don't see why you need that abstract base class there. Preferring composition over inheritance; I think the more reasonable solution would be to have:
public class FooServiceImpl implements FooService {
...
And then clients such as
public class UrlFooService implements FooService {
private final FooService delegatee;
public UrlFooService(URL url) {
delegate = new FooServiceImpl(url.openStream())
...
#Override
Optional<Foo> getFoo(Bar bar) { return delegatee.getFoo(bar); }
Inheritance couples your concrete service classes with that parent class; I would prefer to avoid, by using this simple "delegatee" mechanism.
Please note: I also changed the ctor of the UrlSerivce to take a URL. You already have the types there, so why bother to call new yourself? That just means that your UrlService would have to deal with all the things that could go wrong there!

There's a couple of challenges with your question here and I would start by breaking down the problem a little differently.
As #sisyphus said, watch out for those things you're doing in the constructor. A constructor really should be focused on just creating a "valid object" and nothing more. Many good ideas from #GhostCat too.
Instead think of modeling the problem as follows:
Create an interface that represents the API for your service. In this case if you want it to be "getFoo()" then great. Consider what you would want to pass (is it really the file or a URL or path). Since you said it was a big file, it might not be a great idea to instantiate a big object in memory that you're going to be parsing again into a useful format. You'll definitely pay the price in garbage collection.
Next you should think of separating out the "finding" of the file - or opening the stream with the parsing logic. There are plenty of exceptions that can occur when simply trying to open the file - from it not being found, to not having permissions, to having too many open files (ulimit).
When it comes to parsing, I would suggest that you consider to get really clear on what you are parsing and for what. If this is a real-world problem, 'stable formats' are always subject to change - especially when it comes to tolerating 'invalid' formats - like the existence of other non-printable characters or an unexpected EOF. There will be a lot of demands to handle things gracefully and also a need to understand the stats of what was parsed, what had errors and how to handle that.
My 2 cents.

Related

How to add functionality of Java implementation which changing existing code?

Let's say I've an implementation of fund transfer. Now I want to add authentication functionality which should be done before fund transfer (considering we are already receiving username and password in existing request). Which pattern should we use and how we can achieve this without modifying calling class and existing implementation?
What I can think of at this moment is using decorator pattern after extending implementation class, but I believe still we will be required to modify the calling class.
Please find existing Interface and classes.
package sb.test.demo.fundtransfer;
public interface FundTransferService {
public boolean makeTransfer(TransferRequest request) throws Exception;
}
package sb.test.demo.fundtransfer;
public class FundTransferServiceImpl implements FundTransferService {
#Override
public boolean makeTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("TransferDone");
return true;
}
}
package sb.test.demo.fundtransfer;
public class TestTransfer {
public static void main(String[] args) throws Exception {
TransferRequest request = new TransferRequest();
request.setSourceAccount(123456);
request.setDestinationAccount(654321);
request.setTranserAmount(1000);
request.setUserName("user1");
request.setPassword("pass1");
FundTransferService fts = new FundTransferServiceImpl();
fts.makeTransfer(request);
}
}
Now, I want want extend FundTransferServiceImpl to createFundTransferServiceNEWImpl which will add authentication.
package sb.test.demo.fundtransfer;
public class FundTransferServiceNEWImpl extends FundTransferServiceImpl {
#Override
public boolean makeTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("Authenticating..");
super.makeTransfer(request);
System.out.println("TransferDone from NEW..");
return true;
}
}
Now, without changing TestTransfer.java and FundTransferServiceImpl.java how can I invoke makeTransfer of FundTransferServiceNEWImpl to add authentication? Or, is there any other way to achieve the same?
Please can anyone help me on this?
Thanks in advance!
you can make "FundTransferServiceNEWImpl" also implement the interface "FundTransferService" and provide the implementation that you wish in this only, if this was what you asked for!!
Now, without changing TestTransfer.java and FundTransferServiceImpl.java how can I invoke makeTransfer of FundTransferServiceNEWImpl to add authentication?
You can't without changing the bytecode of either TestTransfer (the caller) or FundTransferServiceImpl (the callee).
There are two ways to change the bytecode.
You can
edit the source file and compile
edit the bytecode before the class is loaded
Edit the source file
I would suggest to edit the TestTransfer class. The problematic line is
FundTransferService fts = new FundTransferServiceImpl();
because this line introduces the dependency from TestTransfer to FundTransferServiceImpl.
I would also suggest to implement the decorator by composition and not inheritence. E.g.
public class AuthenticationFundTransferServiceWrapper implements FundTransferService {
private FundTransferService fundTransferService;
public AuthenticationFundTransferServiceWrapper(FundTransferService fundTransferService){
this.fundTransferService = fundTransferService;
}
public boolean makeTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("Authenticating..");
fundTransferService.makeTransfer(request);
System.out.println("TransferDone from NEW..");
return true;
}
}
The advantage is that the AuthenticationFundTransferServiceWrapper does only depend on the interface FundTransferService and not the implementation. This reduces dependencies and makes the class more flexible.
Editing the byte code
Editing the bytecode before the class is loaded is possible.
Take a look at
AOP (aspect oriented programming)
AspectJ
ASM (bytecode manipulation)
cglib
So you've identified decorator pattern and this answer implemented decorator correctly, but as this is a SOLID principles question I'm going to point out the flaw in that option.
To see the flaw in either inheritance or decorator, consider what happens when the authorization fails. If it throws a new exception type, that is a Liskov Substitution Principle Violation. If it changes the behavior by silently not transferring the funds, that is also an LSP violation. If you're going to rely on the boolean returned, you're not going to get a useful failure message back to the user or system admin.
As I see it, there is no way the client code can avoid knowing that the new implementation is checking authorized as it needs to handle either a new exception, or different return values.
Given that, I would recommend you add a new class, like this:
public final class TransactionAuthorizationService {
private final FundTransferService fundTransferService;
public AuthenticationFundTransferServiceWrapper(FundTransferService fundTransferService){
this.fundTransferService = fundTransferService;
}
public boolean authorizeAndMakeAndTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("Authenticating..");
fundTransferService.makeTransfer(request);
System.out.println("TransferDone from NEW..");
return true;
}
}
Advantages:
Where before client code dealt with the interface FundTransferService you would have no idea until runtime which implementation they had and whether they would be authorizing transactions, now the client code now deals with the TransactionAuthorizationService and they call authorizeAndMakeAndTransfer so it is very clear.
As our new class is not implementing an existing interface, there is no Liskov Substitution Violation and is free to return different values or throw different exceptions.
Other tips:
Stop decorating methods with throw alls: throws Exception
Don't use InterfaceImpl as class names, look for what makes them concrete over the abstract interface.

Solving LazyInitializationException via ignorance

There are countless questions here, how to solve the "could not initialize proxy" problem via eager fetching, keeping the transaction open, opening another one, OpenEntityManagerInViewFilter, and whatever.
But is it possible to simply tell Hibernate to ignore the problem and pretend the collection is empty? In my case, not fetching it before simply means that I don't care.
This is actually an XY problem with the following Y:
I'm having classes like
class Detail {
#ManyToOne(optional=false) Master master;
...
}
class Master {
#OneToMany(mappedBy="master") List<Detail> details;
...
}
and want to serve two kinds of requests: One returning a single master with all its details and another one returning a list of masters without details. The result gets converted to JSON by Gson.
I've tried session.clear and session.evict(master), but they don't touch the proxy used in place of details. What worked was
master.setDetails(nullOrSomeCollection)
which feels rather hacky. I'd prefer the "ignorance" as it'd be applicable generally without knowing what parts of what are proxied.
Writing a Gson TypeAdapter ignoring instances of AbstractPersistentCollection with initialized=false could be a way, but this would depend on org.hibernate.collection.internal, which is surely no good thing. Catching the exception in the TypeAdapter doesn't sound much better.
Update after some answers
My goal is not to "get the data loaded instead of the exception", but "how to get null instead of the exception"
I
Dragan raises a valid point that forgetting to fetch and returning a wrong data would be much worse than an exception. But there's an easy way around it:
do this for collections only
never use null for them
return null rather than an empty collection as an indication of unfetched data
This way, the result can never be wrongly interpreted. Should I ever forget to fetch something, the response will contain null which is invalid.
You could utilize Hibernate.isInitialized, which is part of the Hibernate public API.
So, in the TypeAdapter you can add something like this:
if ((value instanceof Collection) && !Hibernate.isInitialized(value)) {
result = new ArrayList();
}
However, in my modest opinion your approach in general is not the way to go.
"In my case, not fetching it before simply means that I don't care."
Or it means you forgot to fetch it and now you are returning wrong data (worse than getting the exception; the consumer of the service thinks the collection is empty, but it is not).
I would not like to propose "better" solutions (it is not topic of the question and each approach has its own advantages), but the way that I solve issues like these in most use cases (and it is one of the ways commonly adopted) is using DTOs: Simply define a DTO that represents the response of the service, fill it in the transactional context (no LazyInitializationExceptions there) and give it to the framework that will transform it to the service response (json, xml, etc).
What you can try is a solution like the following.
Creating an interface named LazyLoader
#FunctionalInterface // Java 8
public interface LazyLoader<T> {
void load(T t);
}
And in your Service
public class Service {
List<Master> getWithDetails(LazyLoader<Master> loader) {
// Code to get masterList from session
for(Master master:masterList) {
loader.load(master);
}
}
}
And call this service like below
Service.getWithDetails(new LazyLoader<Master>() {
public void load(Master master) {
for(Detail detail:master.getDetails()) {
detail.getId(); // This will load detail
}
}
});
And in Java 8 you can use Lambda as it is a Single Abstract Method (SAM).
Service.getWithDetails((master) -> {
for(Detail detail:master.getDetails()) {
detail.getId(); // This will load detail
}
});
You can use the solution above with session.clear and session.evict(master)
I have raised a similar question in the past (why dependent collection isn't evicted when parent entity is), and it has resulted an answer which you could try for your case.
The solution for this is to use queries instead of associations (one-to-many or many-to-many). Even one of the original authors of Hibernate said that Collections are a feature and not an end-goal.
In your case you can get better flexibility of removing the collections mapping and simply fetch the associated relations when you need them in your data access layer.
You could create a Java proxy for every entity, so that every method is surrounded by a try/catch block that returns null when a LazyInitializationException is catched.
For this to work, all your entities would need to implement an interface and you'd need to reference this interface (instead of the entity class) all throughout your program.
If you can't (or just don't want) to use interfaces, then you could try to build a dynamic proxy with javassist or cglib, or even manually, as explained in this article.
If you go by common Java proxies, here's a sketch:
public static <T> T ignoringLazyInitialization(
final Object entity,
final Class<T> entityInterface) {
return (T) Proxy.newProxyInstance(
entityInterface.getClassLoader(),
new Class[] { entityInterface },
new InvocationHandler() {
#Override
public Object invoke(
Object proxy,
Method method,
Object[] args)
throws Throwable {
try {
return method.invoke(entity, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getTargetException();
if (cause instanceof LazyInitializationException) {
return null;
}
throw cause;
}
}
});
}
So, if you have an entity A as follows:
public interface A {
// getters & setters and other methods DEFINITIONS
}
with its implementation:
public class AImpl implements A {
// getters & setters and other methods IMPLEMENTATIONS
}
Then, assuming you have a reference to the entity class (as returned by Hibernate), you could create a proxy as follows:
AImpl entityAImpl = ...; // some query, load, etc
A entityA = ignoringLazyInitialization(entityAImpl, A.class);
NOTE 1: You'd need to proxy collections returned by Hibernate as well (left as an excersice to the reader) ;)
NOTE 2: Ideally, you should do all this proxying stuff in a DAO or in some type of facade, so that everything is transparent to the user of the entities
NOTE 3: This is by no means optimal, since it creates a stacktrace for every access to an non-initialized field
NOTE 4: This works, but adds complexity; consider if it's really necessary.

Avoiding ClassNotFoundException while loading class using reflection

I am trying to load a class dynamically through reflection by using the method Class.forname("classname") as given in below code.
Class<? extends Layout> layoutClassName;
try {
layoutClassName = (Class<? extends Layout>) Class.forName(site.getSiteLayout());
} catch (ClassNotFoundException e) {
layoutClassName= DefaultLayout.class;
}
I am trying to load a class dynamically if it is defined by the logged in user (db configuration), otherwise provide the default implementation.
This works fine, but after a statistical analysis we found that approximately 80% of the times default implementation is used.
This means approximately 80% of times an Exception object is created. Since creating exception objects is heavy, I would like to avoid it and use some other logic to Identify if a class is present or not.
Please suggest.
PS: I am not looking for any significant performance boost, I am just trying to clean up my existing code.
I don't know if there's a convenient way to check if class exists without throwing ClassNotFoundException that will work for general case.
Handling ClassNotFoundException seems appropriate and clear in this situation. There are several earlier questions that all recommend to handle exception: 1, 2, 3
But if you really want to:
load layouts dynamically (so, you can't avoid reflection);
load layouts by unrestricted class name (if you don't have configuration, can't build defined and relatively stable list of all layout classes);
minimize ClassNotFoundException for some reason.
then I can suggest to cache layout classes. If you don't have a large number of different layouts something like this might work:
private HashMap<String, Class<? extends List>> layoutsByName = new HashMap<>();
public Class<? extends Layout> getLayout(String name) {
Class<? extends Layout> layoutClass = layoutsByName.get(name);
if(layoutClass!=null) {
return layoutClass;
}
layoutClass = getLayoutUsingReflection(name);
layoutsByName.put(name, layoutClass);
return layoutClass;
}
private Class<? extends Layout> getLayoutUsingReflection(String name) {
try {
return (Class<? extends Layout>) Class.forName(name);
} catch (ClassNotFoundException e) {
return DefaultLayout.class;
}
}
This way you won't check for the same layout twice.
As you said...
I am trying to load a class dynamically if it is defined in configuration
Is the 'configuration' is mentiond in some file.
I hope you can get hold of the configuration file(or the configuration status), and create the object for the class only and only if it is mentioned to do so. If not apply the default implementation.
If you cant access the configuration i fear there is no other way as far as i know.

Sustainable Method to Provide Additional Information in Exceptions?

I'm looking for a way to provide multiple pieces of information for exceptions back to end users. The obvious solution of extending Exception ends up with text distributed throughput the code, for example
throw new MyException("Bad data", "The data you entered is incorrect", "http://www.example.com/moreinfo/baddata");
and this quickly becomes unworkable.
I then looked at a catalogue approach but that's too centralized and requires jumping around from one file to another every time an exception is thrown. I'm now considering a hybrid approach with a static ErrorInfoMap class that contains mappings from a key to the more detailed information. Each class then has a static section that contains its own error mappings, so using the class which throws the above exception as an example I'd change it to:
throw new MyException("Bad data");
and at the bottom of the class there would be something like:
static {
ErrorInfoMap.put("Bad data", new ErrorInfo("The data you entered is incorrect", "http://www.example.com/moreinfo/baddata"));
// Information for other exceptions thrown by this class goes here
}
which allows an exception handler to fetch the additional information if required. Is this a good way of solving this issue, or is there a better way to handle this?
I'm not sure what exactly you mean by "the catalog approach" (could you provide a reference or more detailed description?) but from the information you provided, it's not clear to me how a static ErrorInfoMap avoids the problem of being "too centralized and [requiring] jumping around from one file to another every time an exception is thrown".
To me there are several options, depending on exactly what you need to accomplish:
Create a root class, ExceptionTemplate that extends Exception and does whatever repeatable behavior you'd like all your exceptions to do. Formatted toString() methods are a good example. Depending on your exact goals, you might like having your exceptions implement a builder pattern, like so:
throw new BadDataException("Supplied data is not valid")
.expected("a positive integer")
.referenceUrl("http://www.example.com/moreinfo/baddata");
Avoid stringly-typed solutions where an enum or subclass will do. If you don't need to define new exception types at runtime (and if you do, that should be a red flag that there's something deeper wrong with your design) and have an enum that contains all the necessary information to construct your exceptions:
public class EnumException extends Exception {
private EnumException() {} // prevent objects from being instantiated elsewhere
public enum Type {
BAD_DATA("Bad Data","Supplied data is not valid", "http://www.example.com/moreinfo/baddata"),
MISSING_DATA("Missing Data","Required data not found", "http://www.example.com/moreinfo/missingdata");
Type(String title, String genericMessage, String url) {
// Store input
}
public EnumException exception() {
// construct your exception
return new EnumException();
}
}
}
Which can be called with something like:
// note no `new` - the exception is returned by the enum
throw EnumException.Type.BAD_DATA.exception().expected("a positive integer");
This has the advantages of ensuring compile-time type safety, while still giving you the flexibility to define different types of Exceptions in one place.
Create lots of exceptions. I'm still not totally sure what objection you have to just creating a bunch of exceptions. You're looking for ways to "provide additional information" but claim that "the obvious solution of extending Exception ends up with text distributed throughput the code". This shouldn't be the case. Every subclass of Exception should hold all the necessary information except what can only be provided at construction time. Therefore there should be minimal "text distributed throughout the code" as any boiler-plate / reusable strings should be in the Exception class, and nowhere else.
public class DocumentedException extends Exception
{
private String title;
private String genericMessage;
private String detailedMessage;
private String url;
// Generally avoid this long constructor, and define subclasses that only need detailedMessage
public DocumentedException(String t, String g, String d, String u) {
super(g + " - " + d); // sets the getMessage() return value to something sane
title = t;
genericMessage = g;
detailedMessage = d;
url = u;
}
public String toString() {
return title.toUpperCase()+"\n"+
genericMessage+"\n"+
detailedMessage+"\n"+
"More info on this error: "+url+"\n";
}
public static class BadData extends DocumentedException {
public BadData(String details) {
super("Bad Data", "Supplied data is not valid", details, "http://www.example.com/moreinfo/baddata");
}
}
public static class MissingData extends DocumentedException {
public MissingData(String details) {
super("Missing Data", "Required data not found", details, "http://www.example.com/moreinfo/missingdata");
}
}
}
Which you can then call simply with:
throw new DocumentedException.BadData("Username cannot contain whitespace");
Of course, if you expected to need to warn against username errors regularly, you could create an additional class:
public static class BadUsername extends BadData {
public BadUsername() {
super("Usernames can only contain letters, numbers, and underscores");
}
}
The goal, again, is to explicitly define a hierarchy of exceptions that handle all cases you anticipate needing to deal with, such that you avoid repeatedly defining the same strings throughout your application. I personally like the group-exceptions-into-inner-classes pattern I used above, it lets you be very explicit with your errors without creating hundreds of silly stub java files you need to look through constantly. I would say that every major package should have an associated exception-holding class that defines all necessary exceptions for that package.
An alternative to your hybrid approach would be to put the error mapping in the exception itself. When MyException is initialised with Bad data add in the ErrorInfo that you've shown, but also provide a range of constructors for MyException that allows you to override or supplement the default definition of what Bad data means.
You could always have "MyException" as the superclass and have the specific types of errors as subtypes of that. In terms of error messages, you can use static constants on the subtypes to store the different types of errors.
E.g
Exception
-> MyException
-> BadDataException
-> InvalidUserException
etc.
Would be throw like so:
throw new BadDataException(BadDataException.DATA_TOO_LONG);

Singleton to read properties file in a Java webapp; correct approach?

My spaghetti monster consumes XML from several different SOAP services, and the URL for each service is hardcoded into the application. I'm in the process of undoing this hardcoding, and storing the URLs in a properties file.
In terms of reading the properties file, I'd like to encompass that logic in a Singleton that can be referenced as needed.
Change this:
accountLookupURL ="http://prodServer:8080/accountLookupService";
To this:
accountLookupURL =urlLister.getURL("accountLookup");
The Singleton would be contained within the urlLister.
I've tended to shy away from the Singleton pattern, only because I've not had to use it, previously. Am I on the right track, here?
Thanks!
IVR Avenger
You haven't said why you need only one of whatever it is which will be getting the URL. If that just involves reading a properties file, I don't think you do need only one. Seems to me that having two threads read the same properties file at the same time isn't a problem at all.
Unless you were thinking of having some object which only reads the properties file once and then caches the contents for future use. But this is a web application, right? So the way to deal with that is to read in the properties when the application starts up, and store them in the application context. There's only one application context, so there's your "only one" object.
As an alternative, did you consider using something like Apache Commons Configuration (or maybe another configuration framework)?
Singletons are appropriate for this scenario, BUT you have to make sure you're doing the singleton right.
So, for example, what Bozhno suggests is not a singleton, it's an ugly concoction of nasty statics that's not mockable, not easily testable, not injectable, and generally comes back to bite you in the ass.
An acceptable singleton is just your average class with one notable exception that it is guaranteed either by itself or by some external factory/framework (e.g Spring IoC) to exist in only one instance. If you go with the first approach, you do something like
private MyUberSingletonClass() {
//..do your constructor stuff, note it's private
}
private static MyUberSingletonClass instance = null;
public static synchronized MyUberSingletonClass instance() {
if (instance == null) {
instance = new MyUberSingletonClass();
}
return instance;
}
public String getUberUsefulStuff(){
return "42";
}
That's acceptable if you don't really feel the need for a factory otherwise, and aren't using any IoC container in your app (good idea to think about using one though). Note the difference from Bozhno's example: this is a good vanilla class where the only static is an instance var and a method to return it. Also note the synchronized keyword required for lazy-initialization.
update: Pascal recommends this very cool post about a better way to lazy-init singletons in the comments below: http://crazybob.org/2007/01/lazy-loading-singletons.html
Based on your suggestions, and the fact that I don't think I have as much access to this application as I'd hoped (a lot of it is abstracted away in compiled code), here's the solution I've cooked up. This is, of course, a stub, and needs to be fleshed out with better exception handling and the like.
public class WebServiceURLs {
private static class WebServiceURLsHolder
{
public static WebServiceURLs webServiceURLs = new WebServiceURLs();
}
private Properties webServiceURLs;
public WebServiceURLs()
{
try
{
Properties newURLProperties = new Properties();
InputStreamReader inputStream = new InputStreamReader(
FileLoader.class.getClassLoader().getResourceAsStream("../../config/URLs.properties") );
newURLProperties.load(inputStream);
webServiceURLs =newURLProperties;
}
catch (Exception e)
{
webServiceURLs =null;
}
}
public String getURLFromKey(String urlKey)
{
if (webServiceURLs==null)
return null;
else
return webServiceURLs.getProperty(urlKey);
}
public static WebServiceURLs getInstance()
{
return WebServiceURLsHolder.webServiceURLs;
}
}
Is this a good effort as my "first" Singleton?
Thanks,
IVR Avenger
To restate the obvious, Singleton is to be used when all client code should talk to a single instance of the class. So, use a Singleton IFF you are certain that you would not want to load multiple properties files at once. Personally, I would want to be able to have that functionality (loading multiple properties files).
Singletons are mutable statics and therefore evil. (Assuming a reasonably useful definition of "singleton".
Any code that uses the static (a transitive relationship), is has assumptions about pretty much everything else (in this case, a web server and the internet). Mutable statics are bad design, and bad design makes many aspects go rotten (dependency, understandability, testing, security, etc).
As an example, the only thing stopping late versions of JUnit 3 being used in a sandbox was loading a configuration file in one static initialiser. If it had used Parameterisation from Above, there would have been no issue.

Categories

Resources