How to load a constant complex object to a stack using LDCInsnNode in ASM - bytecode

I want to use ASM library to create a bytecode method that is capable of returning a constant value at runtime. One of class in the ASM I can use is the LdcInsnNode. So my sample code is:
class Myclass{
final const Object value;
#Override
public MethodNode get(String clsName, String mhName){
int access = Opcodes.ACC_PUBLIC| Opcodes.ACC_STATIC;
MethodNode methodNode = new MethodNode(ASM5, access, mhName, type.toString(), null, null);
methodNode.instructions.add(new LdcInsnNode(value));
Type returnType = Type.getReturnType(type.toMethodDescriptorString());
if(!returnType.getInternalName().equals(Type.getDescriptor(value.getClass))){
methodNode.instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, returnType.getInternalName()));
}
methodNode.instructions.add(new InsnNode(Opcodes.ARETURN));
return new methodNode;
}
}
My question is how to load value when it is an instance of complex type (user-defined class). The document for LdcInsnNode only says:
/**
* The constant to be loaded on the stack. This parameter must be a non null
* {#link Integer}, a {#link Float}, a {#link Long}, a {#link Double}, a
* {#link String} or a {#link org.objectweb.asm.Type}.
public LdcInsnNode(final Object cst) {
super(Opcodes.LDC);
this.cst = cst;
}

You can't.
The LDC* instructions only support (as of Java 7) ints, floats, longs, doubles, Strings, Classes, MethodHandles, and MethodTypes. It's a special instruction for bytecode level constants, not whatever random objects you might like to create.
You can push a null value with aconst_null, but apart from that you'll have to use normal code, i.e. create the object with new, then invokespecial the constructor with the desired arguments.

To add to the accepted answer:
Probably the easiest way to do this is to define your constant class value as a Singleton in a static field of another class. This can either be a class you write in Java or a synthetic class. Then, when you need the value, just use getstatic to put it on the stack.

Related

Clojure - How to Declare a Collection or Vector of a Record

How Can I define a Record Collection or a Vector of Records?
I have this snippet code:
(defrecord Transaction [a, b, c])
I want define a Transaction collection called LastTransactions to implement a function like this:
(defn can-authorize
"Validate Authorization by Transaction"
[^Transaction transaction, ^LastTransactions lastTransactions]
(... business logic)
)
First Question, is that the right way to do that?
Second, How can i declare that structure?
Clojure's type hints don't offer any type validation - you can use Clojure Spec or Plumatic Schema for that. They only serve for the compiler to prevent reflection when Java methods are called on the parameters. For that purpose, you don't need to type hint a vector since Clojure's core functions for collections (first, conj, etc.) by design don't require reflection on standard collections.
However, if you need, you can type-hint the elements that you extract from the lastTransaction sequence, for example:
(defn can-authorize
"Validate Authorization by Transaction"
[^Transaction transaction, lastTransactions]
...
(for [^Transaction t lastTransactions]
(...do-something-with t))
Type-hints are used to avoid reflection. They are not used to statically type function or constructor args.
Just use basic ^java.util.List type-hint instead of ^LastTransactions. In this case, any use of wrong lastTransactions in the body of the function will fail with ClassCastException. However, it won't check the type of elements in that list. To do so, use type hinting everytime you work with elements of lastTransactions.
Example 1 with type hinting:
(defn can-authorize
[^Transaction transaction, ^java.util.List lastTransactions]
(.size lastTransactions)
)
In this case, decompiled java code will look like:
// Decompiling class: user$can_authorize
import clojure.lang.*;
import java.util.*;
public final class user$can_authorize extends AFunction
{
public static Object invokeStatic(final Object transaction, Object lastTransactions) {
final Object o = lastTransactions;
lastTransactions = null;
return ((List)o).size();
}
public Object invoke(final Object transaction, final Object lastTransactions) {
return invokeStatic(transaction, lastTransactions);
}
}
Example 2 without type hinting:
(defn can-authorize [^String transaction, lastTransactions]
(.size lastTransactions))
decompiled to:
// Decompiling class: user$can_authorize
import clojure.lang.*;
public final class user$can_authorize extends AFunction
{
public static Object invokeStatic(final Object transaction, Object lastTransactions) {
final Object target = lastTransactions;
lastTransactions = null;
return Reflector.invokeNoArgInstanceMember(target, "size", false);
}
public Object invoke(final Object transaction, final Object lastTransactions) {
return invokeStatic(transaction, lastTransactions);
}
}
Compare the resulted return statements:
with type hinting
return ((List)o).size();
without type hinting
return Reflector.invokeNoArgInstanceMember(target, "size", false);
PS: code decompiled by using clj-java-decompiler

Why do Static Methods & Enumerations have unexpected behavior in Xamarin Forms? Objects Passed to Static Methods become null & enums are stored as int

I have been using C#/.NET/Visual Studio since 2000, but I just started working with Xamarin Forms recently. It's a pretty great platform, however I have run across a couple of issues that I cannot figure out. (I'm using Visual Studio 2017 Community). I have been researching this behavior extensively, but have had absolutely no luck in obtaining a resolution. I have created a small application which easily reproduces both of these behaviors and would greatly appreciate any expertise that would help me fix my code so it works as expected. The two issues are these:
1) After creating a custom object using new in Xamarin Forms, the object is not null. However, if that object is passed via the parameter list into a static method, it becomes null inside the method. (Note: In my sample applications I placed the static method inside the Form1 and MainPage classes. I did this only to simplify the samples. The behavior is the same when I put the static method into a separate utility class, either static class or normal class.)
2) Custom enumerations are treated as integers instead of the actual enumerated type. For example, if an instance of an enumerated type is given a value of the first item in the enumeration, its value is 0, an integer. Whereas in a Windows application, the value would be the actual enumeration value (e.g., EnumValue1), and its type would be the enumerated type. This can be a problem if one is trying to do comparisons with strings. For example, aEnum.ToString() == "EnumValue1" will return true in a Windows application, but will return false in Xamarin Forms, because aEnum.ToString() will evaluate to "0". This behavior also breaks the tenet of encapsulation in object-oriented programming, in that you aren't supposed to have to know the underlying implementation of a data type in order to properly use it.
Below is the code that reproduces the issues. There are 2 separate projects, one Windows Forms, the other Xamarin Forms. (The Xamarin Forms project was created with .NET Standard code sharing strategy). Both projects use 2 utility classes Enumerations and CustObj, where the only differences are the namespace definitions (namespace WinFormApp.Utilities and namespace XamarinFormsApp.Utilities, respectively). They both reside in a Utilities folder under their respective projects.
Windows Forms "Form1.cs"
using System.Windows.Forms;
using WinFormApp.Utilities;
namespace WinFormApp
{
partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// ENUMERATION TEST
ACustomEnumeration aCE = ACustomEnumeration.EnumValue1;
string aceStr = aCE.ToString();
// PASSING OBJECT TO STATIC METHOD
CustObj aCustObj = new CustObj();
int ii = aCustObj.i;
string ss = aCustObj.s;
Form1.Foo(aCustObj);
}
public static void Foo(CustObj custObj)
{
}
}
}
Xamarin Forms "MainPage.xaml.cs"
using Xamarin.Forms;
using XamarinFormsApp.Utilities;
namespace XamarinFormsApp
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
// ENUMERATION TEST
ACustomEnumeration aCE = ACustomEnumeration.EnumValue1;
string aceStr = aCE.ToString();
// PASSING OBJECT TO STATIC METHOD
CustObj aCustObj = new CustObj();
int ii = aCustObj.i;
string ss = aCustObj.s;
MainPage.Foo(aCustObj);
}
public static void Foo(CustObj custObj)
{
}
}
}
Utility class "Enumerations.cs"
namespace WinFormApp.Utilities (or XamarinFormsApp.Utilities)
{
public enum ACustomEnumeration
{
EnumValue1,
EnumValue2
}
class Enumerations
{
}
}
Utility class "CustObj.cs"
namespace WinFormApp.Utilities (or XamarinFormsApp.Utilities)
{
public class CustObj
{
public ACustomEnumeration _aCEMember;
public int i;
public string s;
public CustObj()
{
this.i = 99;
this.s = "Hello!";
}
}
}
When stepping through the WinFormApp in Visual Studio, one observes the following variables before the call to static method Foo:
aCE with value of EnumValue1 and Type ACustomEnumeration
aceStr with Value of "EnumValue1" and Type string
aCustObj with Type CustObj and data members:
_aCEMember with Value of EnumValue1 and Type ACustomEnumeration
i with Value of 99 and Type int
s with Value of "Hello!" and Type string
ii with Value of 99
ss with Value of Hello!
After stepping into Foo, the parameter is as expected:
custObj with Type CustObj and data members:
_aCEMember with Value of EnumValue1 and Type ACustomEnumeration
i with Value of 99 and Type int
s with Value of "Hello!" and Type string
All variables evaluate as expected. Enumerations evaluate as the actual enumerated value. The custom object is instantiated and its data members are given their appropriate initial values. When the object is passed into the static method, it is passed correctly as a reference type, and retains all of its data inside the method.
Conversely, when stepping through the XamarinFormsApp in Visual Studio, one observes the following variables before the call to static method Foo:
aCE with Value of 0 and Type int (violates encapsulation)
aceStr with Value of "0" and Type string (this demonstrates the problem with how enumerations are evaluated)
aCustObj with Type CustObj and data members:
_aCEMember with no Value or Type at all
i with no Value or Type at all
s with no Value or Type at all
ii with Value of 99
ss with Value of Hello!
After stepping into Foo, the parameter is NOT as expected:
custObj with Value of null and Type CustObj
The problems with enumerations are fairly obvious. But I am very confused as to what is really going on with the custom object. It makes no sense that when I examine an object after its instantiation, that it doesn't show its data members as being initialized. Although it is strange how variables ii and ss are actually given the correct values.
More importantly, the fact that when I pass the object into the static method, it becomes null, is really mind-boggling.
Does anyone have any ideas as to what is happenning, and how to fix it?

Combining functions and consumers with double-column notation

I often use the double-colon notation for brevity.
I am writing the following method that takes a short list of entities, validates them, and saves back to database.
#Override#Transactional
public void bulkValidate(Collection<Entity> transactions)
{
Consumer<Entity> validator = entityValidator::validate;
validator = validator.andThen(getDao()::update);
if (transactions != null)
transactions.forEach(validator);
}
I'd like to know if there is a shorthand syntax avoiding to instantiate the validator variable
Following syntax is invalid ("The target type of this expression must be a functional interface")
transactions.forEach((entityValidator::validate).andThen(getDao()::update));
You could do that, but you would need to cast explicitly...
transactions.forEach(((Consumer<Entity>)(entityValidator::validate))
.andThen(getDao()::update));
The thing is that a method reference like this entityValidator::validate does not have a type, it's a poly expression and it depends on the context.
You could also define a method to combine these Consumers:
#SafeVarargs
private static <T> Consumer<T> combine(Consumer<T>... consumers) {
return Arrays.stream(consumers).reduce(s -> {}, Consumer::andThen);
}
And use it:
transactions.forEach(combine(entityValidator::validate, getDao()::update))

Use of "#this" in Moles delegates

When I set a property of a moled type, it looks like they always require, as the first parameter, an object of the original moled type. I also noticed that some of the examples in the Moles Reference Guide assign this parameter as #this and I am trying to figure out why.
For instance, the original class looks something like this:
public class ProductDAO
{
internal void Insert(Product product, string id)
{
...
}
}
When I go to mole this method, the property is expecting a delegate whose first parameter is always the type of the moled object, in this case, a ProductDAO object. So in this case, the property is expecting a delegate of:
Action<ProductDAO, Product, string>
So do I always have to provide that moled object as the first parameter of my lambda expression? If so, what's the difference in using a regular variable name versus #this? What does #this mean/do?
MProductDAO.AllInstances.InsertProductString = (dao, product, id) => { };
versus
MProductDAO.AllInstances.InsertProductString = (#this, product, id) => { };

ptr_map and pointer

I'm using ptr_map from boost for storing objects derived from some base abstract type.
class Entity { virtual void foo() = 0; };
class Entity1 : public Entity {};
class Entity2 : public Entity {};
boost::ptr_map<string, Entity> someMap; // We could store pointers for abstract type
Inserting works great:
someMap.insert("someKey", new Entity1());
someMap.insert("someKey", new Entity2());
But not returning from map:
template<typename EntityType>
EntityType *GetEntity(const string &entityName)
{
return dynamic_cast<EntityType*>(&someMap[entityName]);
}
GetEntity<Entity1>(entityName);
Now the problem: operator[] of ptr_map returns reference! So in constructur there could be calling type from value.
Now compiler fails with error:
instantiated from ‘EntityType* EntityManager::GetEntity(const std::string&) [with EntityType = Entity1, std::string = std::basic_string<char>]’
error: cannot allocate an object of abstract type ‘Entity’
If there is any method in ptr_map which returns pointer to the value, there woudln't be any problems. What could you say about this?
An oft forgotten fact is that operator[] will instantiate the key if it doesn't exist. This is a problem in your case because the key is abstract.
So instead, use at().
That is,
return dynamic_cast<EntityType*>(&someMap.at(entityName));
For more info, read the "Semantics: lookup" section
BTW, I would question your design decision to expose raw pointers stored within container whose very purpose is to alleviate memory management.

Resources