How to implement iterator for use with Angular Dart - iterator

I'm adding Iterable functionality to a fork of enyo's csvparser.dart for use with Angular Dart. By adding a mixin, the CsvParser works with for..in loops, but fails ng-repeat with a "RangeError: value 0".
I'm doing something wrong by extending Iterator and the IterableMixin but I'm stuck.
stacktrace
RangeError: value 0
STACKTRACE:
#0 Iterator&IterableMixin.elementAt (dart:collection/iterable.dart:190)
#1 Scope.$watchCollection.<anonymous closure> (package:angular/core/scope.dart:397:60)
#2 relaxFnArgs2.<anonymous closure> (package:angular/utils.dart:49:47)
#3 Scope._digestHandleDirty (package:angular/core/scope.dart:613:24)
#4 Scope._digestComputeLastDirty (package:angular/core/scope.dart:564:36)
#5 Scope._digestWhileDirtyLoop (package:angular/core/scope.dart:489:52)
#6 Scope.$digest (package:angular/core/scope.dart:475:28)
#7 _autoDigestOnTurnDone (package:angular/core/scope.dart:153:14)
#8 _rootRun (dart:async/zone.dart:710)
#9 _ZoneDelegate.run (dart:async/zone.dart:440)
#10 NgZone._finishTurn (package:angular/core/zone.dart:91:21)
#11 NgZone._onRunBase (package:angular/core/zone.dart:56:43)
#12 _onRun (package:angular/core/zone.dart:61:15)
#13 _ZoneDelegate.run (dart:async/zone.dart:440)
#14 _CustomizedZone.run (dart:async/zone.dart:650)
#15 NgZone.run (package:angular/core/zone.dart:143:27)
#16 ngBootstrap (package:angular/bootstrap.dart:89:18)
#17 main (http://127.0.0.1:3030/staffing/web/main.dart:36:14)
csvparser.dart
class CsvParser extends Iterator with IterableMixin<CsvLineParser> {
...
Iterator<CsvLineParser> get iterator => this;
main.dart
#NgController(
selector: '[spreadsheet]',
publishAs: 'ctrl')
class SpreadsheetCtrl
{
// "first_name","last_name","company_name","address","city","county","state","zip","phone1","phone2","email","web"
String raw = '''
"James","Butt","Benton, John B Jr","6649 N Blue Gum St","New Orleans","Orleans","LA",70116,"504-621-8927","504-845-1427","jbutt#gmail.com","http ://www.bentonjohnbjr.com"
"Josephine","Darakjy","Chanay, Jeffrey A Esq","4 B Blue Ridge Blvd","Brighton","Livingston","MI",48116,"810-292-9388","810-374- 9840","josephine_darakjy#darakjy.org","http://www.chanayjeffreyaesq.com"
"Art","Venere","Chemel, James L Cpa","8 W Cerritos Ave #54","Bridgeport","Gloucester","NJ","08014","856-636-8749","856-264-4130","art#venere. org","http://www.chemeljameslcpa.com"
''';
CsvParser data;
SpreadsheetCtrl()
{
data = new CsvParser(raw);
}
}
class MyAppModule extends Module {
MyAppModule() {
type(SpreadsheetCtrl);
}
}
void main() {
ngBootstrap(module: new MyAppModule());
}
index.html
<div spreadsheet>
<table>
<tr ng-repeat="row in ctrl.data">
<td ng-repeat="col in row">
{{col}}
</td>
</tr>
</table>
...
<script type="application/dart" src="main.dart"></script>
test.dart
import 'web/csvparser.dart';
main()
{
String raw = '''
"first_name","last_name","company_name","address","city","county","state","zip","phone1","phone2","email","web"
"James","Butt","Benton, John B Jr","6649 N Blue Gum St","New Orleans","Orleans","LA",70116,"504-621-8927","504-845-1427","jbutt#gmail.com","http://www.bentonjohnbjr.com"
"Josephine","Darakjy","Chanay, Jeffrey A Esq","4 B Blue Ridge Blvd","Brighton","Livingston","MI",48116,"810-292-9388","810-374-9840","josephine_darakjy#darakjy.org","http://www.chanayjeffreyaesq.com"
"Art","Venere","Chemel, James L Cpa","8 W Cerritos Ave #54","Bridgeport","Gloucester","NJ","08014","856-636-8749","856-264-4130","art#venere.org","http://www.chemeljameslcpa.com"
''';
CsvParser data = new CsvParser(raw);
for(var row in data)
{
for(var col in row)
{
print('${col}, ');
}
}
}

It seems this doesn't work if the collection and the iterator are the same class (I don't know why).
Create an additional CsvIterator class and return an instance of CsvIterator in the implementation of CsvParser instead of this.
class CsvIterator extends Iterator<CsvLineParser> {
CsvParser data;
MyIterator(this.data);
... // implementation
}
class CsvParser extends Object with IterableMixin<CsvLineParser> {
...
Iterator<CsvLineParser> get iterator => new CsvIterator(this);
}

Related

just_audio SocketException

When I am trying to open a source (url) without the internet on the device (flight mode on), I receive the next logs:
[ +1 ms] flutter: SocketException: Failed host lookup: 'raw.githubusercontent.com' (OS Error: nodename nor servname provided, or not known, errno = 8)
[ +1 ms] flutter:
#0 _NativeSocket.startConnect (dart:io-patch/socket_patch.dart:682:35)
#1 _RawSocket.startConnect (dart:io-patch/socket_patch.dart:1817:26)
#2 RawSocket.startConnect (dart:io-patch/socket_patch.dart:27:23)
#3 RawSecureSocket.startConnect (dart:io/secure_socket.dart:237:22)
#4 SecureSocket.startConnect (dart:io/secure_socket.dart:60:28)
#5 _ConnectionTarget.connect (dart:_http/http_impl.dart:2438:24)
#6 _HttpClient._getConnection.connect (dart:_http/http_impl.dart:2834:12)
#7 _HttpClient._getConnection (dart:_http/http_impl.dart:2839:12)
#8 _HttpClient._openUrl (dart:_http/http_impl.dart:2698:12)
#9 _HttpClient.getUrl (dart:_http/http_impl.dart:2575:48)
#10 _proxyHandlerForUri.handler (package:just_audio/just_audio.dart:3039:46)
#11 _proxyHandlerForUri.handler (package:just_audio/just_audio.dart:3038:23)
#12 _ProxyHttpServer.start.<anonymous closure> (package:just_audio/just_audio.dart:1946:16)
#13 _ProxyHttpServer.start<…>
try/catch doesn't help...
Any advice or idea?
UPDATE:
It take me some time to debug example app and compare with mine.
The issue comes cos I use headers with my source.
Here is piece of code from library, where dramattic change happened:
#override
Future<void> _setup(AudioPlayer player) async {
await super._setup(player);
if (uri.scheme == 'asset') {
_overrideUri = await _loadAsset(uri.pathSegments.join('/'));
} else if (uri.scheme != 'file' &&
!kIsWeb &&
(headers != null || player._userAgent != null)) {
await player._proxy.ensureRunning();
_overrideUri = player._proxy.addUriAudioSource(this);
}
}
we are interested in this particular line:
(headers != null || player._userAgent != null)) {
I use headers, so in my app code goes futher, and then fails inside _proxyHandlerForUri, line 3039.

Realm crash on Results.first.getter

Realm 5.0.2
I'm trying to understand how this crash is possible. It is crashing when calling first on a Realm Results object. I'm guessing this is a concurrency issue, but Realm is instantiated on same thread as query, and the Realm objects are immediately converted to app objects. But if it's not a concurrency issue, then ... what?!
0
Thread 1 Queue : com.apple.main-thread (serial)
#0 0x00000001037d8f7c in realm::IndexArray::index_string_all(realm::StringData, std::__1::vector<realm::ObjKey, std::__1::allocator<realm::ObjKey> >&, realm::ClusterColumn const&) const ()
#1 0x00000001036c8fdc in realm::IntegerNode<realm::ArrayIntNull, realm::Equal>::init() ()
#2 0x00000001036a740c in realm::Query::init() const ()
#3 0x00000001036a74dc in realm::Query::find_all(realm::ConstTableView&, unsigned long, unsigned long, unsigned long) const ()
#4 0x0000000103866e7c in realm::ConstTableView::do_sync() ()
#5 0x00000001036a78d0 in realm::Query::find_all(unsigned long, unsigned long, unsigned long) ()
#6 0x00000001036a7d50 in realm::Query::find_all(realm::DescriptorOrdering const&) ()
#7 0x00000001033af2c4 in realm::Results::do_evaluate_query_if_needed(bool)
#8 0x00000001033aeca8 in realm::util::Optional<realm::Obj> realm::Results::try_get<realm::Obj>(unsigned long)
#9 0x00000001033af01c in realm::util::Optional<realm::Obj> realm::Results::first<realm::Obj>()
#10 0x0000000103542b9c in _ZZN5realm7Results5firstI18RLMAccessorContextEEDaRT_ENKUlTyS4_E_clIPNS_3ObjEEES3_S4_
#11 0x0000000103541d38 in _ZN5realmL14switch_on_typeINS_3ObjEZNS_7Results5firstI18RLMAccessorContextEEDaRT_EUlTyS6_E_EES5_NS_12PropertyTypeEOT0_
#12 0x00000001035418c0 in _ZNK5realm7Results8dispatchIZNS0_5firstI18RLMAccessorContextEEDaRT_EUlTyS5_E_EES4_OS5_
#13 0x0000000103541870 in auto realm::Results::first<RLMAccessorContext>(RLMAccessorContext&)
#14 0x0000000103541834 in -[RLMResults firstObject]::$_8::operator()() const
#15 0x000000010353d5c4 in auto translateRLMResultsErrors<-[RLMResults firstObject]::$_8>(-[RLMResults firstObject]::$_8&&, NSString*)
#16 0x000000010353d544 in -[RLMResults firstObject]
#17 0x0000000104968cf4 in Results.first.getter
#18 0x000000010228e97c in static LibraryManager.LibraryPersistence.findPersistentTag(permanentId:temporaryId:)
#19 0x000000010228e500 in LibraryManager.getTag(forAssignment:)
#20 0x000000010220c284 in closure #1 in AudiobookUserSettings.tags.getter
#21 0x000000019eb5e038 in Sequence.compactMap<A>(_:) ()
#22 0x000000010220c1d0 in AudiobookUserSettings.tags.getter
#23 0x0000000102195e70 in Audiobook.tags.getter
#24 0x000000010226407c in FolderManager.updateFromLibrary()
#25 0x00000001022ca78c in LibraryTableViewController.refreshFolders()
#26 0x00000001022c6930 in closure #1 in LibraryTableViewController.refreshView()
#27 0x0000000102150700 in thunk for #escaping #callee_guaranteed () -> () ()
#28 0x0000000104b7605c in _dispatch_call_block_and_release ()
#29 0x0000000104b774d8 in _dispatch_client_callout ()
#30 0x0000000104b85f64 in _dispatch_main_queue_callback_4CF ()
#31 0x00000001911cc8d4 in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ ()
#32 0x00000001911c758c in __CFRunLoopRun ()
#33 0x00000001911c6bc8 in CFRunLoopRunSpecific ()
#34 0x000000019b5a85cc in GSEventRunModal ()
#35 0x0000000195379744 in UIApplicationMain ()
#36 0x00000001023d838c in main
#37 0x0000000191043384 in start ()
Enqueued from audiobookSettings-persistence (Thread 33) Queue
#0 0x0000000104b7bdd0 in dispatch_async ()
#1 0x00000001c807004c in OS_dispatch_queue.async(group:qos:flags:execute:) ()
#2 0x00000001022c6808 in LibraryTableViewController.refreshView()
#3 0x00000001022c6288 in closure #1 in LibraryTableViewController.viewWillAppear(_:)
The relevant code from the app:
func getTag(forAssignment assignment: TagAssignment) -> Tag? {
let tag = LibraryPersistence.findPersistentTag(permanentId: assignment.permanentTagId,
temporaryId: assignment.temporaryTagId)
return tag?.toTag()
}
static func findPersistentTag(permanentId: Int? = nil, temporaryId: String? = nil) -> PersistentTag? {
guard let userId = getIdForCurrentUser() else {
return nil
}
let realm = try! Realm()
// First try lookup by permanent tag id
if let permanentId = permanentId {
let permanentIdNumber = NSNumber(value: permanentId)
if let stored = realm.objects(PersistentTag.self).filter("permanentId == %# AND userId == %#", permanentIdNumber, userId).first {
return stored
}
}
// Then try temporary tag id
if let temporaryId = temporaryId {
return realm.objects(PersistentTag.self).filter("temporaryId == %# AND userId == %#", temporaryId, userId).first
}
return nil
}
UPDATE: More crash details:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
#0: 0x0000000103bfc2fd Realm`realm::util::EncryptedFileMapping::read_barrier(void const*, unsigned long, unsigned long (*)(char const*)) + 29
* frame #1: 0x00000001035ce000 Realm`realm::util::do_encryption_read_barrier(addr=0x00007fff87a95540, size=8, header_to_size=(Realm`realm::NodeHeader::get_byte_size_from_header(char const*) at node_header.hpp:201), mapping=0xca4c51df08c18be5)(char const*), realm::util::EncryptedFileMapping*) at file_mapper.hpp:133:14
#2: 0x0000000103b496ee Realm`realm::IndexArray::index_string_all(realm::StringData, std::__1::vector<realm::ObjKey, std::__1::allocator<realm::ObjKey> >&, realm::ClusterColumn const&) const + 398
...
It looks like you're not the only one with this problem.
https://github.com/realm/realm-cocoa/issues/6556
This looks like a problem with 5.0.x, some have downgraded to 4.x to remove the problem. It references another issue (bottom of the report) which has been fixed and merged, but not yet released.
I'd read the bug report and see if this follows your experience, then either (a) follow the workaround, or (b) downgrade to 4.4.x. Watch the fix issue (https://github.com/realm/realm-core/pull/3828) for being included in a new release.

Getting Seg Fault when I try to dynamically load a custom library (.so) which is compiled with webkit2gtk library

I have created a shared library which has a function displaywebview that launches a GTK window and loads the URL into it using webkit2gtk.
Now I am writing a caller program which loads this library using dlopen, gets the method displaywebview using dlsym and calls this function.
I get a seg fault inside displaywebview at the point where I call webkit_web_view_new(). Could someone help me out on why this is happening?
webkit_main.so
#include <gtk/gtk.h>
#include <webkit2/webkit2.h>
extern "C"
{
int displayWebView();
}
int displayWebView()
{
printf("Entered in displayWebView\n");
// Initialize GTK+
gtk_init(NULL, NULL);
// Create an 800x600 window that will contain the browser instance
GtkWidget *main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(main_window), 800, 600);
WebKitWebView *webView = (WebKitWebView*)webkit_web_view_new();
// webkit_web_view_new();
// // Put the browser area into the main window
gtk_container_add(GTK_CONTAINER(main_window), GTK_WIDGET(webView));
// Set up callbacks so that if either the main window or the browser instance is
// closed, the program will exit
g_signal_connect(main_window, "destroy", G_CALLBACK(destroyWindowCb), NULL);
g_signal_connect(webView, "close", G_CALLBACK(closeWebViewCb), main_window);
// // Load a web page into the browser instance
webkit_web_view_load_uri(webView, "http://www.gmail.com");
// // Make sure that when the browser area becomes visible, it will get mouse
// // and keyboard events
gtk_widget_grab_focus(GTK_WIDGET(webView));
// // Make sure the main window and all its contents are visible
gtk_widget_show_all(main_window);
// // Run the main GTK+ event loop
gtk_main();
return 0;
}
caller.cpp
#include <unistd.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
typedef int (*PDISPLAYWEBVIEW)();
int main(){
void* hnd = dlopen("/home/radix/Desktop/webkit_socket/webkit_main.so", RTLD_LAZY);
// sleep(10);
if(hnd!=NULL){
PDISPLAYWEBVIEW pdisplayWebView = (PDISPLAYWEBVIEW)dlsym(hnd,"displayWebView");
if(pdisplayWebView == NULL){
printf("dlsym error %s", dlerror());
}
else{
printf("Everything okay, launch the function\n");
(*pdisplayWebView)();
}
dlclose(hnd);
}
else{
printf("The error is %s", dlerror());
}
}
BACKTRACE details:
Thread 1 "caller" received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x00007ffff790d165 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x00007ffff2009168 in bmalloc::Scavenger::Scavenger(std::lock_guard<bmalloc::Mutex>&) () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#3 0x00007ffff1d12f61 in bmalloc::PerProcess<bmalloc::Scavenger>::getSlowCase() () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#4 0x00007ffff2001fcc in bmalloc::Heap::Heap(bmalloc::HeapKind, std::lock_guard<bmalloc::Mutex>&) () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#5 0x00007ffff1fff1ff in bmalloc::PerProcess<bmalloc::PerHeapKind<bmalloc::Heap> >::getSlowCase() () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#6 0x00007ffff1ffee99 in bmalloc::Cache::Cache(bmalloc::HeapKind) () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#7 0x00007ffff1fff311 in bmalloc::PerThread<bmalloc::PerHeapKind<bmalloc::Cache> >::getSlowCase() () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#8 0x00007ffff1ffef0d in bmalloc::Cache::allocateSlowCaseNullCache(bmalloc::HeapKind, unsigned long) () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#9 0x00007ffff1af22a2 in JSC::ExecutableAllocator::initializeAllocator() () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#10 0x00007ffff1d0bf25 in ?? () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#11 0x00007ffff0926739 in __pthread_once_slow (once_control=0x7ffff22a6ff0, init_routine=0x7ffff790c120 <__once_proxy>) at pthread_once.c:116
#12 0x00007ffff1d0d90d in JSC::initializeThreading() () from /usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so.18
#13 0x00007ffff49beb29 in ?? () from /usr/lib/x86_64-linux-gnu/libwebkit2gtk-4.0.so.37
#14 0x00007ffff4aa4add in ?? () from /usr/lib/x86_64-linux-gnu/libwebkit2gtk-4.0.so.37
#15 0x00007ffff4b0eb00 in ?? () from /usr/lib/x86_64-linux-gnu/libwebkit2gtk-4.0.so.37
#16 0x00007ffff0e5e777 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#17 0x00007ffff0e5fc0d in g_object_newv () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#18 0x00007ffff0e603c4 in g_object_new () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#19 0x00007ffff4b0ab7d in ?? () from /usr/lib/x86_64-linux-gnu/libwebkit2gtk-4.0.so.37
#20 0x00007ffff0ba74a5 in g_once_impl () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#21 0x00007ffff4b31cc9 in webkit_web_view_new () from /usr/lib/x86_64-linux-gnu/libwebkit2gtk-4.0.so.37
#22 0x00007ffff6d96f0f in displayWebView () at webkit_main.cpp:81
#23 0x00005555555548df in main () at caller.cpp:20
Note:
When I use the same program with webkitgtk-1.0 it runs absolutely fine. With webkit2gtk-4.0 it gives this issue.
When I compile caller.cpp with libwebkit2gtk-4.0 it strangely doesn't give seg fault anymore.
Could someone help me out why this is happening?
I am using debian 9 with webkit2gtk-4.0-37 of version: 2.22.2-1~bpo9+1
There are some compiler options that have to be the same within every components (object modules, libraries, shared objects) so that they could work together.
Other than -pthread, large-file-support (in 32-bit) comes to my mind.
Another possible source of problems if different versions of a component are linked together.

Jaguar orm - reflexive relationship

Does jaguar_orm support reflexive relationships?
I have a Category class that can be part of another Category:
class Category {
/// constructor
Category();
Category.make(this.id, this.name);
/// fields
#PrimaryKey()
int id;
#Column(isNullable: false)
String name;
#BelongsTo(CategoryBean, isNullable: true, refCol: 'id')
int parentCategoryId;
/// database
// String toString() => "Product($id, $name, $parentCategoryId)";
String toString() => "Product($id, $name)";
}
When I try to create one I get a stack overflow as follows:
Exception while parsing field: id!
Stack Overflow
#0 _Uri._uriEncode (dart:core/runtime/liburi_patch.dart:34:3)
#1 _Uri._makePath.<anonymous closure> (dart:core/uri.dart:2116:23)
#2 ListIterable.join (dart:_internal/iterable.dart)
#3 _Uri._makePath (dart:core/uri.dart:2117:12)
#4 _SimpleUri.replace (dart:core/uri.dart:4358:19)
#5 urlOfElement (package:source_gen/src/utils.dart:87:11)
#6 _MirrorTypeChecker.isExactly (package:source_gen/src/type_checker.dart:264:49)
#7 _ListBase&Object&ListMixin.any (dart:collection/list.dart)
#8 TypeChecker.isAssignableFromType (package:source_gen/src/type_checker.dart:162:57)
#9 ParsedBean._makeField.<anonymous closure> (package:jaguar_orm_gen/src/parser/parser.dart:351:47)
#10 WhereIterator.moveNext (dart:_internal/iterable.dart)
#11 MappedIterator.moveNext (dart:_internal/iterable.dart:391:19)
#12 new List.from (dart:core/runtime/libarray_patch.dart:40:17)
#13 ParsedBean._makeField (package:jaguar_orm_gen/src/parser/parser.dart:472:34)
#14 ParsedBean._parseFields (package:jaguar_orm_gen/src/parser/parser.dart:325:21)
#15 ParsedBean.detect (package:jaguar_orm_gen/src/parser/parser.dart:74:5)
#16 ParsedBean.detect (package:jaguar_orm_gen/src/parser/parser.dart:85:56)
This repeats for some time.
Is there something special I need to do, to prevent the stack overflow?
You need to add a #HasOne or #HasMany decorator depending of your case.

Using Javassist, how do I add code to an empty loop?

Using Javassist 3.20.0.GA, I am trying to inject code in to an empty loop.
Everything I try, I keep running in to a java.lang.VerifyError error at the point I attempt to create a new instance of the modified class.
I've attempted to isolate the issue to a small program that fails to run successfully.
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.Bytecode;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.CodeIterator;
import javassist.bytecode.InstructionPrinter;
import javassist.bytecode.MethodInfo;
import javassist.compiler.Javac;
public class EmptyLoopTest {
private void testEmptyLoopModification() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get(EmptyLoopTest.class.getName() + "$EmptyLoopClass");
CtMethod m = cc.getDeclaredMethod("emptyLoopMethod");
printMethod("Before modifications", m);
MethodInfo methodInfo = m.getMethodInfo();
CodeAttribute ca = methodInfo.getCodeAttribute();
CodeIterator ci = ca.iterator();
Javac jv = new Javac(cc);
jv.compileStmnt("System.out.println(\"injected into loop\");");
Bytecode b = jv.getBytecode();
adjustCodeAttributeIfNeeded(b, ca);
ci.insertAt(0, b.get());
printMethod("After modifications", m);
Class c = cc.toClass();
logInfo("Attempting to create instance of modified class");
c.newInstance();
}
private void adjustCodeAttributeIfNeeded(Bytecode b, CodeAttribute ca){
int locals = b.getMaxLocals();
int stack = b.getMaxStack();
if(stack > ca.getMaxStack()) {
ca.setMaxStack(stack);
}
if(locals > ca.getMaxLocals()) {
ca.setMaxLocals(locals);
}
}
private void printMethod(String title, CtMethod m){
logInfo(title);
InstructionPrinter instructionPrinter = new InstructionPrinter(System.out);
instructionPrinter.print(m);
}
private void logInfo(String message){
System.out.println("");
System.out.println("------" + message);
}
public class EmptyLoopClass {
public void emptyLoopMethod() {
for(;;){
}
}
}
public static void main(String[] args) throws Exception {
// have errors written to sysout so all output from this program is in order
System.setErr(System.out);
new EmptyLoopTest().testEmptyLoopModification();
}
}
When I run this program, the following is written to the console..
------Before modifications
0: goto 0
------After modifications
0: getstatic #32 = Field java.lang.System.out(Ljava/io/PrintStream;)
3: ldc #34 = "injected into loop"
5: invokevirtual #40 = Method java.io.PrintStream.println((Ljava/lang/String;)V)
8: goto 8
------Attempting to create instance of modified class
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 8
Exception Details:
Location:
EmptyLoopTest$EmptyLoopClass.emptyLoopMethod()V #8: goto
Reason:
Expected stackmap frame at this location.
Bytecode:
0x0000000: b200 2012 22b6 0028 a700 00
Stackmap Table:
same_frame(#0)
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructor0(Class.java:3075)
at java.lang.Class.newInstance(Class.java:412)
at EmptyLoopTest.testEmptyLoopModification(EmptyLoopTest.java:35)
at EmptyLoopTest.main(EmptyLoopTest.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Process finished with exit code 1
If everything was working as expected, I'd expect the goto instruction after modifications to goto 0 instead of what it's currently showing, goto 8. It's as if the StackMapTable wasn't adjusted appropriately when I invoked javassist.bytecode.CodeIterator#insertAt.
Can anyone spot what I'm doing wrong here?
Thanks,
Eric
you create class like this c.newInstance(); so it supposed to have 0-parameters constructor - to be static inner class
public static class EmptyLoopClass {
public void emptyLoopMethod() {
for(;;){
}
}
you should call methodInfo.rebuildStackMap(cp); after code modifications. JVM uses StackMap to validate class file.
Anyway you are ending up with bytecode
3: ldc #34 = "injected into loop"
5: invokevirtual #40 = Method java.io.PrintStream.println((Ljava/lang/String;)V)
8: goto 8
This code is not inside the loop, it is before loop. Actual loop is single instruction 8: goto 8 and you have to generate some additional loop code if you want to inject instructions inside it.