How to get private fields and call private methods in Advice wrapped method? - byte-buddy

Redefine method:
private <T> void redefine(Class<T> type, UnaryOperator<DynamicType.Builder<T>> operation) {
DynamicType.Builder<T> builder = new ByteBuddy().redefine(type);
ClassLoader systemClassLoader = Entity.class.getClassLoader();
operation
.apply(builder)
.make()
.load(systemClassLoader, ClassReloadingStrategy.fromInstalledAgent());
}
Use of Advice:
redefine(ChunkGeneratorAbstract.class, builder -> builder
.method(named("buildNoise")
.and(takesArguments(3)))
.intercept(Advice.to(ChunkGeneratorAdvice.class).wrap(StubMethod.INSTANCE)));
ChunkGeneratorAdvice:
#Advice.OnMethodExit
public static void buildNoise(GeneratorAccess generatoraccess, StructureManager structuremanager, IChunkAccess ichunkaccess,
#Advice.This ChunkGeneratorAbstract chunkGenerator) {
int val = chunkGenerator.n;
Object someVal = chunkGenerator.privateMethod();
}
chunkGenerator.n is a private field. How to get its value?
Also, how i can call private methods like chunkGenerator.privateMethod()?

For a private field, you can use Advice.FieldValue as an annotation on a parameter to read and write from it. For a method call, you would need to use a MemberSubstitution. You would then declare an empty method in the advice class that has the same signature and call this method from your advice code. Later, you would use MemberSubstitution to switch the method calls.

Related

Kotlin object, an implementation vs instance

In Objects in Kotlin: Create safe singletons in one line of code (KAD 27) Antonio Leiva states:
In fact, an object is just a data type with a single implementation.
I would expect to see the term instance rather than implementation used here. Is there some nuance that I am missing?
Sure it does have a single instance after all, but I believe what they meant to say is that whatever you write in an object is final and you can not override it. Even if you make it open(for argument purpose), you can not make an anonymous object out of it since the anonymous class can't be used on a SingleTon instance.
So " data type with a single implementation" means, whatever you write is the final implementation. An instance is, after all, a result of some implementation.
For reference, I am adding a decompiled code of object declaration.
public final class Test {
#NotNull
private static final String testMember = "Test";
public static final Test INSTANCE;
#NotNull
public final String getTestMember() {
return testMember;
}
private Test() {
}
static {
Test var0 = new Test();
INSTANCE = var0;
testMember = "Test";
}
}

Kotlin: data class private setter public getter

Is there any way I can make a private setter and a public getter in a Kotlin Data Class?
data class Test(var attribute: String) {
// attribute can be mutated inside this class
// but outside only readable ?
}
A simple approach would be to have a private var, but then to provide a public property that delegates to it:
data class Test (private var attribute_ : String) {
val attribute: String get() = attribute_
}
To add some background to the other answer:
There's no way to do this directly in the constructor, though there have been several proposals as to how it could be added to the language; see here.
If it weren't a data class, I'd suggest this alternative:
class Test(_attribute: String) {
var attribute = _attribute
private set
}
That only stores one value in the object, so is marginally more efficient.
But since this is a data class, that's not possible.  (Data classes can't have non-properties in their primary constructors.)  So the other answer's suggestion seems best.

NSubstitute throws CouldNotSetReturnDueToTypeMismatchException when mocking Query on NHibernate Session

I have a repository offering a GetAll method which again calls the Query extension method on the ISession instance of NHibernate.
public ICollection<Product> GetAll()
{
return _session.Query<Product>().ToList();
}
My unit test looks like this:
[Test]
public void GetAllReturnsCollectionFromSession()
{
IQueryable<Product> productList = new ProductListBuilder().Build().AsQueryable();
_fixture.Session.Query<Product>().Returns(productList);
var sut = _fixture.CreateSut();
var result = sut.GetAll();
Assert.AreSame(productList, result);
_fixture.Session.Received().Query<Product>();
}
In the _fixture.Session.Query().Returns(productList) statement, NSubstitute throws the following exception:
NSubstitute.Exceptions.CouldNotSetReturnDueToTypeMismatchException : Can not return value of type IQueryable`1Proxy for ISession.GetSessionImplementation (expected type ISessionImplementor).
Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)),
and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).
If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member.
Return values cannot be configured for non-virtual/non-abstract members.
Correct use:
mySub.SomeMethod().Returns(returnValue);
Potentially problematic use:
mySub.SomeMethod().Returns(ConfigOtherSub());
Instead try:
var returnValue = ConfigOtherSub();
mySub.SomeMethod().Returns(returnValue);
at NSubstitute.Core.ConfigureCall.CheckResultIsCompatibleWithCall(IReturn valueToReturn, ICallSpecification spec)
at NSubstitute.Core.ConfigureCall.SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs)
at NSubstitute.Core.CallRouter.LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs)
at NSubstitute.Core.SubstitutionContext.LastCallShouldReturn(IReturn value, MatchArgs matchArgs)
at NSubstitute.SubstituteExtensions.Returns[T](MatchArgs matchArgs, T returnThis, T[] returnThese)
at NSubstitute.SubstituteExtensions.ReturnsForAnyArgs[T](T value, T returnThis, T[] returnThese)
at Statoil.Wellcom.DataLayer.Implementation.Oracle.UnitTests.Repositories.DwapplicationRepositoryTests.GetAllReturnsCollectionFromSession() in C:\git\WELLCOM\source\Statoil.Wellcom.DataLayer.Implementation.Oracle.UnitTests\Repositories\DwapplicationRepositoryTests.cs:line 123
It looks like NSubstitute is unable to set the return value due to Query being an extension method. How would I go about mocking the extension method call on the ISession?
The easiest solution is to wrap your ISession in another interface/concrete class so you can stub that out:
public interface ISessionWrapper
{
IQueryable<T> Query<T>();
}
public class SessionWrapper : ISessionWrapper
{
private readonly ISession _session;
public SessionWrapper(ISession session)
{
_session = session;
}
public IQueryable<T> Query<T>()
{
return _session.Query<T>();
}
}
There is no way to mock extension method with NSubstitute, however if you know what extension method is using inside, than you can mock that. Your test will use extension method on mocked object and eventually it will use mocked method. Difficult part is to know what is going on inside.
It worked for me in projects, where I knew all the source code and I could check what's inside.

Returning a class object in java equivalent for objective-C

I have a Java class where I'm returning the class objects using the add method. I'm trying to write an equivalent Obj-C method. Should I have to declare the objective C method as void and update the class variables inside the method?
public class TesCodeRequest{
private String apiKey;
private String apiSecret;
private String endpoint;
public TesCodeRequest(String apiKey, String apiSecret, String endpoint) {
//initialization done here
}
public TesCodeRequest add(String endpoint, Object... fields) {
//method
}
}
Expected add method in Obj-c
-(void)add:(NSString *)endPoint andObject:(NSArray *field{
//endpoint and other variables to be updated here.
}
If I understand you right, you should declare init method with you parameter (if you parameters is private, otherwise you can assign it after standart init) and call it form add:
-(TesCodeRequest *)add:(NSString *)endPoint andObject:(NSArray *field{
//endpoint and other variables to be updated here.
TesCodeRequest *testCodeRequest = [[TesCodeRequest alloc] initWithEndPoint:endPoint ...];
return testCodeRequest;
}
If you want call this method without create instance of TesCodeRequest, use class method (+(TesCodeRequest *)add:(NSString *)endPoint andObject:(NSArray *field{)

How should I treat variables that aren't necessarily class properties but are used by several methods?

I occasionally find myself with several methods in a class that all require the same data (for example, a query object). Typically, there will be one public method with a generic name like parseReport() which in turn delegates work out to several private methods and finally returns the finished product:
public function parseReport( queryObject ) {
queryObject = correctDatesAndTimes( queryObject );
queryObject = sortByCusomter( queryObject );
queryObject = buildHierarchy( queryObject );
return queryObject;
}
private function correctDatesAndTimes( queryObject ) {
// do some stuff
return queryObject;
}
private function sortByCusomter( queryObject ) {
// do some stuff
return queryObject;
}
private function buildHierarchy( queryObject ) {
// do some stuff
return queryObject;
}
So my question is, should my queryObject be a class-level property that all of my methods will reference rather than passing it through as an argument to the method each time it is called?
In a case like this, queryObject should not be a class property. If you look at it, you actually have one big function that is split in several smaller functions. If it was one big function, you wouldn't make a class property of it.
Data belongs in a class property, when the data is actually a part of the class. Remember that
a class definition is the encapsulating of both data and behavior.
In your example you need to pass the query object as a parameter, as it will be changed inside the private function.
Additionally putting it into a private property will give you headaches if you go multithreaded.